Revert "Merge branch 'reformat_code'"

This reverts commit daf3b57e89, reversing
changes made to 7a6e0b7d77.
This commit is contained in:
NovaSquirrel 2021-03-10 11:13:28 -05:00
parent fe90e80881
commit c0e249e993
573 changed files with 65158 additions and 82299 deletions

View file

@ -17,28 +17,22 @@ void AluMulDiv::Run(bool isRead)
{
uint64_t cpuCycle = _cpu->GetCycleCount();
if (isRead)
{
if(isRead) {
//Run 1 cycle less for read operations, since they occur earlier within the CPU cycle, compared to a write
cpuCycle--;
}
if (_multCounter != 0 || _divCounter != 0)
{
if(_multCounter != 0 || _divCounter != 0) {
uint64_t cyclesToRun = cpuCycle - _prevCpuCycle;
while (cyclesToRun--)
{
if (!_multCounter && !_divCounter)
{
while(cyclesToRun--) {
if(!_multCounter && !_divCounter) {
break;
}
if (_multCounter > 0)
{
if(_multCounter > 0) {
_multCounter--;
if (_state.DivResult & 0x01)
{
if(_state.DivResult & 0x01) {
_state.MultOrRemainderResult += _shift;
}
@ -46,14 +40,12 @@ void AluMulDiv::Run(bool isRead)
_state.DivResult >>= 1;
}
if (_divCounter > 0)
{
if(_divCounter > 0) {
_divCounter--;
_shift >>= 1;
_state.DivResult <<= 1;
if (_state.MultOrRemainderResult >= _shift)
{
if(_state.MultOrRemainderResult >= _shift) {
_state.MultOrRemainderResult -= _shift;
_state.DivResult |= 1;
}
@ -68,8 +60,7 @@ uint8_t AluMulDiv::Read(uint16_t addr)
{
Run(true);
switch (addr)
{
switch(addr) {
case 0x4214: return (uint8_t)_state.DivResult;
case 0x4215: return (uint8_t)(_state.DivResult >> 8);
@ -84,14 +75,11 @@ void AluMulDiv::Write(uint16_t addr, uint8_t value)
{
Run(false);
switch (addr)
{
case 0x4202: _state.MultOperand1 = value;
break;
switch(addr) {
case 0x4202: _state.MultOperand1 = value; break;
case 0x4203:
_state.MultOrRemainderResult = 0;
if (!_divCounter && !_multCounter)
{
if(!_divCounter && !_multCounter) {
_multCounter = 8;
_state.MultOperand2 = value;
@ -100,16 +88,13 @@ void AluMulDiv::Write(uint16_t addr, uint8_t value)
}
break;
case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value;
break;
case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8);
break;
case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value; break;
case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8); break;
case 0x4206:
_state.MultOrRemainderResult = _state.Dividend;
if (!_divCounter && !_multCounter)
{
if(!_divCounter && !_multCounter) {
_divCounter = 16;
_state.Divisor = value;
_shift = (value << 16);
@ -125,11 +110,10 @@ AluState AluMulDiv::GetState()
return _state;
}
void AluMulDiv::Serialize(Serializer& s)
void AluMulDiv::Serialize(Serializer &s)
{
s.Stream(
_state.MultOperand1, _state.MultOperand2, _state.MultOrRemainderResult, _state.Dividend, _state.Divisor,
_state.DivResult,
_state.MultOperand1, _state.MultOperand2, _state.MultOrRemainderResult, _state.Dividend, _state.Divisor, _state.DivResult,
_divCounter, _multCounter, _shift, _prevCpuCycle
);
}

View file

@ -8,7 +8,7 @@ class Cpu;
class AluMulDiv final : public ISerializable
{
private:
Cpu* _cpu;
Cpu *_cpu;
uint64_t _prevCpuCycle = 0;
@ -28,5 +28,5 @@ public:
AluState GetState();
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

@ -9,84 +9,60 @@
#include "DisassemblyInfo.h"
#include "LabelManager.h"
static const std::regex instRegex = std::regex(
"^\\s*([a-zA-Z]{3})[\\s]*(#%|#){0,1}([([]{0,1})[\\s]*([$]{0,1})([^\\[\\],)(;:]*)[\\s]*((,[$][0-9a-f]{1,2}|,x\\)|\\),y|,x|,y|,s\\),y|,s|\\)|\\],y|\\]){0,1})\\s*(;*)(.*)",
std::regex_constants::icase);
static const std::regex instRegex = std::regex("^\\s*([a-zA-Z]{3})[\\s]*(#%|#){0,1}([([]{0,1})[\\s]*([$]{0,1})([^\\[\\],)(;:]*)[\\s]*((,[$][0-9a-f]{1,2}|,x\\)|\\),y|,x|,y|,s\\),y|,s|\\)|\\],y|\\]){0,1})\\s*(;*)(.*)", std::regex_constants::icase);
static const std::regex isCommentOrBlank = std::regex("^\\s*([;]+.*$|\\s*$)", std::regex_constants::icase);
static const std::regex labelRegex = std::regex("^\\s*([@_a-zA-Z][@_a-zA-Z0-9]*):(.*)", std::regex_constants::icase);
static const std::regex byteRegex = std::regex(
"^\\s*[.]db\\s+((\\$[a-fA-F0-9]{1,2}[ ])*)(\\$[a-fA-F0-9]{1,2})+\\s*(;*)(.*)$", std::regex_constants::icase);
static const std::regex byteRegex = std::regex("^\\s*[.]db\\s+((\\$[a-fA-F0-9]{1,2}[ ])*)(\\$[a-fA-F0-9]{1,2})+\\s*(;*)(.*)$", std::regex_constants::icase);
void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output,
std::unordered_map<string, uint32_t>& labels, bool firstPass,
std::unordered_map<string, uint32_t>& currentPassLabels)
void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint32_t>& labels, bool firstPass, std::unordered_map<string, uint32_t>& currentPassLabels)
{
//Remove extra spaces as part of processing
size_t offset = code.find_first_of(',', 0);
if (offset != string::npos)
{
if(offset != string::npos) {
code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end());
}
offset = code.find_first_of(')', 0);
if (offset != string::npos)
{
if(offset != string::npos) {
code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end());
}
//Determine if the line is blank, a comment, a label or code
std::smatch match;
if (std::regex_search(code, match, byteRegex))
{
if(std::regex_search(code, match, byteRegex)) {
vector<string> bytes = StringUtilities::Split(match.str(1) + match.str(3), ' ');
for (string& byte : bytes)
{
for(string& byte : bytes) {
output.push_back((uint8_t)(HexUtilities::FromHex(byte.substr(1))));
instructionAddress++;
}
output.push_back(AssemblerSpecialCodes::EndOfLine);
}
else if (std::regex_search(code, match, labelRegex))
{
} else if(std::regex_search(code, match, labelRegex)) {
string label = match.str(1);
string afterLabel = match.str(2);
if (currentPassLabels.find(match.str(1)) != currentPassLabels.end())
{
if(currentPassLabels.find(match.str(1)) != currentPassLabels.end()) {
output.push_back(AssemblerSpecialCodes::LabelRedefinition);
}
else
{
} else {
labels[match.str(1)] = instructionAddress;
currentPassLabels[match.str(1)] = instructionAddress;
ProcessLine(afterLabel, instructionAddress, output, labels, firstPass, currentPassLabels);
}
return;
}
else if (std::regex_search(code, match, isCommentOrBlank))
{
} else if(std::regex_search(code, match, isCommentOrBlank)) {
output.push_back(AssemblerSpecialCodes::EndOfLine);
return;
}
else if (std::regex_search(code, match, instRegex) && match.size() > 1)
{
} else if(std::regex_search(code, match, instRegex) && match.size() > 1) {
LineData lineData;
AssemblerSpecialCodes result = GetLineData(match, lineData, labels, firstPass);
if (result == AssemblerSpecialCodes::OK)
{
if(result == AssemblerSpecialCodes::OK) {
AssembleInstruction(lineData, instructionAddress, output, firstPass);
}
else
{
} else {
output.push_back(result);
}
}
else
{
} else {
output.push_back(AssemblerSpecialCodes::ParsingError);
}
}
AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass)
AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass)
{
bool isBinary = match.str(2).length() > 1 && match.str(2)[1] == '%'; //Immediate + binary: "#%"
@ -98,93 +74,68 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineDa
lineData.HasOpeningParenthesis = match.str(3) == "(";
lineData.HasOpeningBracket = match.str(3) == "[";
std::transform(lineData.OperandSuffix.begin(), lineData.OperandSuffix.end(), lineData.OperandSuffix.begin(),
::toupper);
std::transform(lineData.OperandSuffix.begin(), lineData.OperandSuffix.end(), lineData.OperandSuffix.begin(), ::toupper);
std::transform(lineData.OpCode.begin(), lineData.OpCode.end(), lineData.OpCode.begin(), ::toupper);
bool foundSpace = false;
for (char c : match.str(5))
{
if (c != ' ' && c != '\t')
{
if (foundSpace)
{
for(char c : match.str(5)) {
if(c != ' ' && c != '\t') {
if(foundSpace) {
//can't have spaces in operands (except at the very end)
return AssemblerSpecialCodes::InvalidSpaces;
}
else if (lineData.IsHex && !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')))
{
} else if(lineData.IsHex && !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) {
//invalid hex
return AssemblerSpecialCodes::InvalidHex;
}
else if (isBinary && c != '0' && c != '1')
{
} else if(isBinary && c != '0' && c != '1') {
return AssemblerSpecialCodes::InvalidBinaryValue;
}
lineData.Operand.push_back(c);
}
else
{
} else {
foundSpace = true;
}
}
if (isBinary)
{
if(isBinary) {
//Convert the binary value to hex
if (lineData.Operand.size() == 0)
{
if(lineData.Operand.size() == 0) {
return AssemblerSpecialCodes::MissingOperand;
}
else if (lineData.Operand.size() <= 8)
{
} else if(lineData.Operand.size() <= 8) {
lineData.IsHex = true;
int value = 0;
for (size_t i = 0; i < lineData.Operand.size(); i++)
{
for(size_t i = 0; i < lineData.Operand.size(); i++) {
value <<= 1;
value |= lineData.Operand[i] == '1' ? 1 : 0;
}
lineData.Operand = HexUtilities::ToHex(value, false);
}
else
{
} else {
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
if (!lineData.HasComment && !match.str(9).empty())
{
if(!lineData.HasComment && !match.str(9).empty()) {
//something is trailing at the end of the line, and it's not a comment
return AssemblerSpecialCodes::TrailingText;
}
if (!lineData.IsHex)
{
if(!lineData.IsHex) {
bool allNumeric = true;
for (size_t i = 0; i < lineData.Operand.size(); i++)
{
if (lineData.Operand[i] == '-' && i == 0 && lineData.Operand.size() > 1)
{
for(size_t i = 0; i < lineData.Operand.size(); i++) {
if(lineData.Operand[i] == '-' && i == 0 && lineData.Operand.size() > 1) {
//First char is a minus sign, and more characters follow, continue
continue;
}
if ((lineData.Operand[i] < '0' || lineData.Operand[i] > '9'))
{
if((lineData.Operand[i] < '0' || lineData.Operand[i] > '9')) {
allNumeric = false;
break;
}
}
if (allNumeric && !lineData.Operand.empty())
{
if(allNumeric && !lineData.Operand.empty()) {
//Operand is not empty, and it only contains decimal values
lineData.IsDecimal = true;
}
else
{
} else {
lineData.IsDecimal = false;
}
}
@ -192,292 +143,175 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineDa
return GetAddrModeAndOperandSize(lineData, labels, firstPass);
}
AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass)
AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass)
{
int opSize = 0;
bool invalid = false;
string operand = lineData.Operand;
if (lineData.IsHex)
{
if (operand.size() == 0)
{
if(lineData.IsHex) {
if(operand.size() == 0) {
return AssemblerSpecialCodes::MissingOperand;
}
else if (operand.size() <= 2)
{
} else if(operand.size() <= 2) {
opSize = 1;
}
else if (operand.size() <= 4)
{
} else if(operand.size() <= 4) {
opSize = 2;
}
else if (operand.size() <= 6)
{
} else if(operand.size() <= 6) {
opSize = 3;
}
else
{
} else {
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
else if (lineData.IsDecimal)
{
} else if(lineData.IsDecimal) {
int value = std::stoi(operand.c_str());
if (value < -0x800000)
{
if(value < -0x800000) {
//< -2^23 is invalid
return AssemblerSpecialCodes::OperandOutOfRange;
}
else if (value < -0x8000)
{
} else if(value < -0x8000) {
opSize = 3;
}
else if (value < -0x80)
{
} else if(value < -0x80) {
opSize = 2;
}
else if (value <= 0xFF)
{
} else if(value <= 0xFF) {
opSize = 1;
}
else if (value <= 0xFFFF)
{
} else if(value <= 0xFFFF) {
opSize = 2;
}
else if (value <= 0xFFFFFF)
{
} else if(value <= 0xFFFFFF) {
opSize = 3;
}
else
{
} else {
//>= 2^23 is invalid
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
else if (!operand.empty())
{
} else if(!operand.empty()) {
//Check if the operand is a known label
auto findResult = labels.find(operand);
if (findResult != labels.end())
{
if(findResult != labels.end()) {
lineData.Operand = HexUtilities::ToHex((uint16_t)findResult->second);
lineData.IsHex = true;
opSize = 2;
}
else if (operand.size() == 1 && (operand[0] == 'A' || operand[0] == 'a') && lineData.OperandSuffix.empty() && !
lineData.IsHex && !lineData.IsImmediate && !lineData.HasOpeningParenthesis && !lineData.HasOpeningBracket)
{
} else if(operand.size() == 1 && (operand[0] == 'A' || operand[0] == 'a') && lineData.OperandSuffix.empty() && !lineData.IsHex && !lineData.IsImmediate && !lineData.HasOpeningParenthesis && !lineData.HasOpeningBracket) {
//Allow optional "A" after AddrMode == Accumulator instructions
lineData.Mode = AddrMode::Acc;
opSize = 0;
}
else
{
} else {
int32_t addr = _labelManager->GetLabelRelativeAddress(operand);
if (addr > 0xFFFF)
{
if(addr > 0xFFFF) {
lineData.Operand = HexUtilities::ToHex24(addr);
lineData.IsHex = true;
opSize = 3;
}
else if (addr > 0xFF)
{
} else if(addr > 0xFF) {
lineData.Operand = HexUtilities::ToHex((uint16_t)addr);
lineData.IsHex = true;
opSize = 2;
}
else if (addr >= 0)
{
} else if(addr >= 0) {
lineData.Operand = HexUtilities::ToHex((uint8_t)addr);
lineData.IsHex = true;
opSize = 1;
}
else
{
if (firstPass)
{
} else {
if(firstPass) {
//First pass, we couldn't find a matching label, so it might be defined later on
//Pretend it exists for now
_needSecondPass = true;
lineData.Operand = "FFFF";
lineData.IsHex = true;
opSize = 2;
}
else
{
} else {
return AssemblerSpecialCodes::UnknownLabel;
}
}
}
}
else
{
} else {
//No operand
opSize = 0;
}
if (lineData.Mode == AddrMode::Imp)
{
if (lineData.OperandSuffix.substr(0, 2) == ",$")
{
if(lineData.Mode == AddrMode::Imp) {
if(lineData.OperandSuffix.substr(0, 2) == ",$") {
//Used by MVP, MVN
opSize = 2;
lineData.Mode = AddrMode::BlkMov;
uint8_t dest = HexUtilities::FromHex(lineData.OperandSuffix.substr(2));
lineData.Operand += HexUtilities::ToHex(dest);
}
else if (lineData.IsImmediate)
{
if (lineData.HasOpeningParenthesis || lineData.HasOpeningBracket || opSize == 0)
{
} else if(lineData.IsImmediate) {
if(lineData.HasOpeningParenthesis || lineData.HasOpeningBracket|| opSize == 0) {
invalid = true;
}
else if (opSize >= 3)
{
} else if(opSize >= 3) {
invalid = true;
}
lineData.Mode = opSize == 2 ? AddrMode::Imm16 : AddrMode::Imm8; //or Rel
} else if(lineData.HasOpeningBracket) {
if(lineData.OperandSuffix == "]") {
switch(opSize){
case 1: lineData.Mode = AddrMode::DirIndLng; break;
case 2: lineData.Mode = AddrMode::AbsIndLng; break;
default: invalid = true; break;
}
else if (lineData.HasOpeningBracket)
{
if (lineData.OperandSuffix == "]")
{
switch (opSize)
{
case 1: lineData.Mode = AddrMode::DirIndLng;
break;
case 2: lineData.Mode = AddrMode::AbsIndLng;
break;
default: invalid = true;
break;
}
}
else if (lineData.OperandSuffix == "],Y")
{
if (opSize == 1)
{
} else if(lineData.OperandSuffix == "],Y") {
if(opSize == 1) {
lineData.Mode = AddrMode::DirIndLngIdxY;
}
else
{
} else {
invalid = true;
}
}
}
else if (lineData.HasOpeningParenthesis)
{
if (lineData.OperandSuffix == ")")
{
} else if(lineData.HasOpeningParenthesis) {
if(lineData.OperandSuffix == ")") {
lineData.Mode = opSize == 1 ? AddrMode::DirInd : AddrMode::AbsInd;
}
else if (lineData.OperandSuffix == ",X)")
{
} else if(lineData.OperandSuffix == ",X)") {
lineData.Mode = opSize == 1 ? AddrMode::DirIdxIndX : AddrMode::AbsIdxXInd;
}
else if (lineData.OperandSuffix == "),Y")
{
if (opSize == 1)
{
} else if(lineData.OperandSuffix == "),Y") {
if(opSize == 1) {
lineData.Mode = AddrMode::DirIndIdxY;
}
else
{
} else {
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
else if (lineData.OperandSuffix == ",S),Y")
{
if (opSize == 1)
{
} else if(lineData.OperandSuffix == ",S),Y") {
if(opSize == 1) {
lineData.Mode = AddrMode::StkRelIndIdxY;
}
else
{
} else {
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
else
{
} else {
invalid = true;
}
}
else
{
if (lineData.OperandSuffix == ",X")
{
if (opSize == 3)
{
} else {
if(lineData.OperandSuffix == ",X") {
if(opSize == 3) {
lineData.Mode = AddrMode::AbsLngIdxX;
}
else if (opSize == 2)
{
} else if(opSize == 2) {
lineData.Mode = AddrMode::AbsIdxX;
}
else if (opSize == 1)
{
} else if(opSize == 1) {
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::DirIdxX;
}
else
{
} else {
invalid = true;
}
}
else if (lineData.OperandSuffix == ",Y")
{
if (opSize == 2)
{
} else if(lineData.OperandSuffix == ",Y") {
if(opSize == 2) {
lineData.Mode = AddrMode::AbsIdxY;
}
else if (opSize == 1)
{
} else if(opSize == 1) {
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::DirIdxY;
}
else
{
} else {
invalid = true;
}
}
else if (lineData.OperandSuffix == ",S")
{
if (opSize == 1)
{
} else if(lineData.OperandSuffix == ",S") {
if(opSize == 1) {
lineData.Mode = AddrMode::StkRel;
}
else
{
} else {
return AssemblerSpecialCodes::OperandOutOfRange;
}
}
else if (lineData.OperandSuffix.empty())
{
if (opSize == 0)
{
} else if(lineData.OperandSuffix.empty()) {
if(opSize == 0) {
lineData.Mode = AddrMode::Imp; //or Acc
}
else if (opSize == 3)
{
} else if(opSize == 3) {
lineData.Mode = AddrMode::AbsLng;
}
else if (opSize == 2)
{
} else if(opSize == 2) {
lineData.Mode = AddrMode::Abs;
}
else if (opSize == 1)
{
} else if(opSize == 1) {
//Sometimes zero page addressing is not available, even if the operand is in the zero page
lineData.Mode = AddrMode::Dir;
}
else
{
} else {
invalid = true;
}
}
else
{
} else {
invalid = true;
}
}
@ -497,60 +331,41 @@ bool Assembler::IsOpModeAvailable(string& opCode, AddrMode mode)
return _availableModesByOpName[opCode].find((int)mode) != _availableModesByOpName[opCode].end();
}
void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output,
bool firstPass)
void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output, bool firstPass)
{
bool foundMatch = false;
for (int i = 0; i < 256; i++)
{
for(int i = 0; i < 256; i++) {
AddrMode opMode = CpuDisUtils::OpMode[i];
if (lineData.OpCode == CpuDisUtils::OpName[i])
{
if(lineData.OpCode == CpuDisUtils::OpName[i]) {
bool modeMatch = opMode == lineData.Mode;
if (!modeMatch)
{
if (lineData.Mode == AddrMode::Imp && (opMode == AddrMode::Acc || opMode == AddrMode::Stk))
{
if(!modeMatch) {
if(lineData.Mode == AddrMode::Imp && (opMode == AddrMode::Acc || opMode == AddrMode::Stk)) {
modeMatch = true;
}
else if (lineData.Mode == AddrMode::Imm8 && opMode == AddrMode::Sig8)
{
} else if(lineData.Mode == AddrMode::Imm8 && opMode == AddrMode::Sig8) {
modeMatch = true;
}
else if ((lineData.Mode == AddrMode::Imm8 || lineData.Mode == AddrMode::Imm16) && (opMode == AddrMode::ImmX
|| opMode == AddrMode::ImmM))
{
} else if((lineData.Mode == AddrMode::Imm8 || lineData.Mode == AddrMode::Imm16) && (opMode == AddrMode::ImmX || opMode == AddrMode::ImmM)) {
modeMatch = true;
}
else if ((opMode == AddrMode::Rel || opMode == AddrMode::RelLng) && (lineData.Mode == AddrMode::AbsLng ||
lineData.Mode == AddrMode::Abs || lineData.Mode == AddrMode::Dir))
{
} else if((opMode == AddrMode::Rel || opMode == AddrMode::RelLng) && (lineData.Mode == AddrMode::AbsLng || lineData.Mode == AddrMode::Abs || lineData.Mode == AddrMode::Dir)) {
bool lngBranch = opMode == AddrMode::RelLng;
modeMatch = true;
//Convert "absolute" jump to a relative jump
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
if (lineData.Mode == AddrMode::Abs)
{
if(lineData.Mode == AddrMode::Abs) {
value |= (instructionAddress & 0xFF0000);
}
int32_t addressGap;
if (lineData.Mode == AddrMode::Dir)
{
if(lineData.Mode == AddrMode::Dir) {
addressGap = (int8_t)value;
}
else
{
} else {
addressGap = value - (instructionAddress + (lngBranch ? 3 : 2));
}
if (addressGap > (lngBranch ? 32767 : 127) || addressGap < (lngBranch ? -32768 : -128))
{
if(addressGap > (lngBranch ? 32767 : 127) || addressGap < (lngBranch ? -32768 : -128)) {
//Gap too long, can't jump that far
if (!firstPass)
{
if(!firstPass) {
//Pretend this is ok on first pass, we're just trying to find all labels
output.push_back(AssemblerSpecialCodes::OutOfRangeJump);
return;
@ -560,30 +375,22 @@ void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAdd
//Update data to match relative jump
lineData.OperandSize = lngBranch ? 2 : 1;
lineData.IsHex = true;
lineData.Operand = lngBranch
? HexUtilities::ToHex((uint16_t)addressGap)
: HexUtilities::ToHex((uint8_t)addressGap);
lineData.Operand = lngBranch ? HexUtilities::ToHex((uint16_t)addressGap) : HexUtilities::ToHex((uint8_t)addressGap);
}
}
if (modeMatch)
{
if(modeMatch) {
output.push_back(i);
instructionAddress += (lineData.OperandSize + 1);
if (lineData.OperandSize == 1)
{
if(lineData.OperandSize == 1) {
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
}
else if (lineData.OperandSize == 2)
{
} else if(lineData.OperandSize == 2) {
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
output.push_back((value >> 8) & 0xFF);
}
else if (lineData.OperandSize == 3)
{
} else if(lineData.OperandSize == 3) {
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
output.push_back(value & 0xFF);
output.push_back((value >> 8) & 0xFF);
@ -596,12 +403,9 @@ void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAdd
}
}
if (!foundMatch)
{
if(!foundMatch) {
output.push_back(AssemblerSpecialCodes::InvalidInstruction);
}
else
{
} else {
output.push_back(AssemblerSpecialCodes::EndOfLine);
}
}
@ -617,10 +421,8 @@ Assembler::~Assembler()
uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode)
{
for (uint8_t i = 0; i < 255; i++)
{
if (_availableModesByOpName.find(CpuDisUtils::OpName[i]) == _availableModesByOpName.end())
{
for(uint8_t i = 0; i < 255; i++) {
if(_availableModesByOpName.find(CpuDisUtils::OpName[i]) == _availableModesByOpName.end()) {
_availableModesByOpName[CpuDisUtils::OpName[i]] = std::unordered_set<int>();
}
_availableModesByOpName[CpuDisUtils::OpName[i]].emplace((int)CpuDisUtils::OpMode[i]);
@ -637,17 +439,13 @@ uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* as
vector<string> codeLines;
codeLines.reserve(100);
while (i < code.size())
{
while(i < code.size()) {
size_t offset = code.find_first_of('\n', i);
string line;
if (offset != string::npos)
{
if(offset != string::npos) {
line = code.substr(i, offset - i);
i = offset + 1;
}
else
{
} else {
line = code.substr(i);
i = code.size();
}
@ -656,18 +454,15 @@ uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* as
//Make 2 passes - first one to find all labels, second to assemble
_needSecondPass = false;
for (string& line : codeLines)
{
for(string& line : codeLines) {
ProcessLine(line, startAddress, output, temporaryLabels, true, currentPassLabels);
}
if (_needSecondPass)
{
if(_needSecondPass) {
currentPassLabels.clear();
output.clear();
startAddress = originalStartAddr;
for (string& line : codeLines)
{
for(string& line : codeLines) {
ProcessLine(line, startAddress, output, temporaryLabels, false, currentPassLabels);
}
}

View file

@ -28,13 +28,9 @@ private:
bool _needSecondPass;
shared_ptr<LabelManager> _labelManager;
void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output,
std::unordered_map<string, uint32_t>& labels, bool firstPass,
std::unordered_map<string, uint32_t>& currentPassLabels);
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass);
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels,
bool firstPass);
void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint32_t>& labels, bool firstPass, std::unordered_map<string, uint32_t>& currentPassLabels);
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass);
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass);
void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output, bool firstPass);
bool IsOpModeAvailable(string& opCode, AddrMode mode);

View file

@ -38,16 +38,13 @@ BaseCartridge::~BaseCartridge()
delete[] _saveRam;
}
shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile)
shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile)
{
if (romFile.IsValid())
{
if(romFile.IsValid()) {
shared_ptr<BaseCartridge> cart(new BaseCartridge());
if (patchFile.IsValid())
{
if(patchFile.IsValid()) {
cart->_patchPath = patchFile;
if (romFile.ApplyPatch(patchFile))
{
if(romFile.ApplyPatch(patchFile)) {
MessageManager::DisplayMessage("Patch", "ApplyingPatch", patchFile.GetFileName());
}
}
@ -55,8 +52,7 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, Virtu
vector<uint8_t> romData;
romFile.ReadFile(romData);
if (romData.size() < 0x4000)
{
if(romData.size() < 0x4000) {
return nullptr;
}
@ -64,35 +60,24 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, Virtu
cart->_romPath = romFile;
string fileExt = FolderUtilities::GetExtension(romFile.GetFileName());
if (fileExt == ".bs")
{
if(fileExt == ".bs") {
cart->_bsxMemPack.reset(new BsxMemoryPack(console, romData, false));
if (!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize))
{
if(!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize)) {
return nullptr;
}
}
else if (fileExt == ".gb" || fileExt == ".gbc")
{
if (cart->LoadGameboy(romFile, true))
{
} else if(fileExt == ".gb" || fileExt == ".gbc") {
if(cart->LoadGameboy(romFile, true)) {
return cart;
}
else
{
} else {
return nullptr;
}
}
else
{
if (romData.size() < 0x8000)
{
} else {
if(romData.size() < 0x8000) {
return nullptr;
}
cart->_prgRomSize = (uint32_t)romData.size();
if ((cart->_prgRomSize & 0xFFF) != 0)
{
if((cart->_prgRomSize & 0xFFF) != 0) {
//Round up to the next 4kb size, to ensure we have access to all the rom's data
cart->_prgRomSize = (cart->_prgRomSize & ~0xFFF) + 0x1000;
}
@ -101,27 +86,19 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, Virtu
memcpy(cart->_prgRom, romData.data(), romData.size());
}
if (memcmp(cart->_prgRom, "SNES-SPC700 Sound File Data", 27) == 0)
{
if (cart->_prgRomSize >= 0x10200)
{
if(memcmp(cart->_prgRom, "SNES-SPC700 Sound File Data", 27) == 0) {
if(cart->_prgRomSize >= 0x10200) {
//SPC files must be 0x10200 bytes long at minimum
cart->LoadSpc();
}
else
{
} else {
return nullptr;
}
}
else
{
} else {
cart->LoadRom();
}
return cart;
}
else
{
} else {
return nullptr;
}
}
@ -129,8 +106,7 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, Virtu
int32_t BaseCartridge::GetHeaderScore(uint32_t addr)
{
//Try to figure out where the header is by using a scoring system
if (_prgRomSize < addr + 0x7FFF)
{
if(_prgRomSize < addr + 0x7FFF) {
return -1;
}
@ -139,55 +115,42 @@ int32_t BaseCartridge::GetHeaderScore(uint32_t addr)
uint32_t score = 0;
uint8_t mode = (cartInfo.MapMode & ~0x10);
if ((mode == 0x20 || mode == 0x22) && addr < 0x8000)
{
if((mode == 0x20 || mode == 0x22) && addr < 0x8000) {
score++;
}
else if ((mode == 0x21 || mode == 0x25) && addr >= 0x8000)
{
} else if((mode == 0x21 || mode == 0x25) && addr >= 0x8000) {
score++;
}
if (cartInfo.RomType < 0x08)
{
if(cartInfo.RomType < 0x08) {
score++;
}
if (cartInfo.RomSize < 0x10)
{
if(cartInfo.RomSize < 0x10) {
score++;
}
if (cartInfo.SramSize < 0x08)
{
if(cartInfo.SramSize < 0x08) {
score++;
}
uint16_t checksum = cartInfo.Checksum[0] | (cartInfo.Checksum[1] << 8);
uint16_t complement = cartInfo.ChecksumComplement[0] | (cartInfo.ChecksumComplement[1] << 8);
if (checksum + complement == 0xFFFF && checksum != 0 && complement != 0)
{
if(checksum + complement == 0xFFFF && checksum != 0 && complement != 0) {
score += 8;
}
uint32_t resetVectorAddr = addr + 0x7FFC;
uint32_t resetVector = _prgRom[resetVectorAddr] | (_prgRom[resetVectorAddr + 1] << 8);
if (resetVector < 0x8000)
{
if(resetVector < 0x8000) {
return -1;
}
uint8_t op = _prgRom[addr + (resetVector & 0x7FFF)];
if (op == 0x18 || op == 0x78 || op == 0x4C || op == 0x5C || op == 0x20 || op == 0x22 || op == 0x9C)
{
if(op == 0x18 || op == 0x78 || op == 0x4C || op == 0x5C || op == 0x20 || op == 0x22 || op == 0x9C) {
//CLI, SEI, JMP, JML, JSR, JSl, STZ
score += 8;
}
else if (op == 0xC2 || op == 0xE2 || op == 0xA9 || op == 0xA2 || op == 0xA0)
{
} else if(op == 0xC2 || op == 0xE2 || op == 0xA9 || op == 0xA2 || op == 0xA0) {
//REP, SEP, LDA, LDX, LDY
score += 4;
}
else if (op == 0x00 || op == 0xFF || op == 0xCC)
{
} else if(op == 0x00 || op == 0xFF || op == 0xCC) {
//BRK, SBC, CPY
score -= 8;
}
@ -198,16 +161,14 @@ int32_t BaseCartridge::GetHeaderScore(uint32_t addr)
void BaseCartridge::LoadRom()
{
//Find the best potential header among lorom/hirom + headerless/headered combinations
vector<uint32_t> baseAddresses = {0, 0x200, 0x8000, 0x8200, 0x408000, 0x408200};
vector<uint32_t> baseAddresses = { 0, 0x200, 0x8000, 0x8200, 0x408000, 0x408200 };
int32_t bestScore = -1;
bool hasHeader = false;
bool isLoRom = true;
bool isExRom = true;
for (uint32_t baseAddress : baseAddresses)
{
for(uint32_t baseAddress : baseAddresses) {
int32_t score = GetHeaderScore(baseAddress);
if (score >= 0 && score >= bestScore)
{
if(score >= 0 && score >= bestScore) {
bestScore = score;
isLoRom = (baseAddress & 0x8000) == 0;
isExRom = (baseAddress & 0x400000) != 0;
@ -219,57 +180,44 @@ void BaseCartridge::LoadRom()
}
uint32_t flags = 0;
if (isLoRom)
{
if (hasHeader)
{
if(isLoRom) {
if(hasHeader) {
flags |= CartFlags::CopierHeader;
}
flags |= CartFlags::LoRom;
}
else
{
if (hasHeader)
{
} else {
if(hasHeader) {
flags |= CartFlags::CopierHeader;
}
flags |= isExRom ? CartFlags::ExHiRom : CartFlags::HiRom;
}
if (flags & CartFlags::CopierHeader)
{
if(flags & CartFlags::CopierHeader) {
//Remove the copier header
memmove(_prgRom, _prgRom + 512, _prgRomSize - 512);
_prgRomSize -= 512;
_headerOffset -= 512;
}
if ((flags & CartFlags::HiRom) && (_cartInfo.MapMode & 0x27) == 0x25)
{
if((flags & CartFlags::HiRom) && (_cartInfo.MapMode & 0x27) == 0x25) {
flags |= CartFlags::ExHiRom;
}
else if ((flags & CartFlags::LoRom) && (_cartInfo.MapMode & 0x27) == 0x22)
{
} else if((flags & CartFlags::LoRom) && (_cartInfo.MapMode & 0x27) == 0x22) {
flags |= CartFlags::ExLoRom;
}
if (_cartInfo.MapMode & 0x10)
{
if(_cartInfo.MapMode & 0x10) {
flags |= CartFlags::FastRom;
}
_flags = (CartFlags::CartFlags)flags;
_hasBattery = (_cartInfo.RomType & 0x0F) == 0x02 || (_cartInfo.RomType & 0x0F) == 0x05 || (_cartInfo.RomType & 0x0F)
== 0x06 || (_cartInfo.RomType & 0x0F) == 0x09 || (_cartInfo.RomType & 0x0F) == 0x0A;
_hasBattery = (_cartInfo.RomType & 0x0F) == 0x02 || (_cartInfo.RomType & 0x0F) == 0x05 || (_cartInfo.RomType & 0x0F) == 0x06 || (_cartInfo.RomType & 0x0F) == 0x09 || (_cartInfo.RomType & 0x0F) == 0x0A;
_coprocessorType = GetCoprocessorType();
if (_coprocessorType != CoprocessorType::None && _cartInfo.ExpansionRamSize > 0 && _cartInfo.ExpansionRamSize <= 7)
{
if(_coprocessorType != CoprocessorType::None && _cartInfo.ExpansionRamSize > 0 && _cartInfo.ExpansionRamSize <= 7) {
_coprocessorRamSize = _cartInfo.ExpansionRamSize > 0 ? 1024 * (1 << _cartInfo.ExpansionRamSize) : 0;
}
if (_coprocessorType == CoprocessorType::GSU && _coprocessorRamSize == 0)
{
if(_coprocessorType == CoprocessorType::GSU && _coprocessorRamSize == 0) {
//Use a min of 64kb by default for GSU games
_coprocessorRamSize = 0x10000;
}
@ -288,10 +236,8 @@ void BaseCartridge::LoadRom()
CoprocessorType BaseCartridge::GetCoprocessorType()
{
if ((_cartInfo.RomType & 0x0F) >= 0x03)
{
switch ((_cartInfo.RomType & 0xF0) >> 4)
{
if((_cartInfo.RomType & 0x0F) >= 0x03) {
switch((_cartInfo.RomType & 0xF0) >> 4) {
case 0x00: return GetDspVersion();
case 0x01: return CoprocessorType::GSU;
case 0x02: return CoprocessorType::OBC1;
@ -299,8 +245,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType()
case 0x04: return CoprocessorType::SDD1;
case 0x05: return CoprocessorType::RTC;
case 0x0E:
switch (_cartInfo.RomType)
{
switch(_cartInfo.RomType) {
case 0xE3: return CoprocessorType::SGB;
case 0xE5: return CoprocessorType::Satellaview;
default: return CoprocessorType::None;
@ -308,8 +253,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType()
break;
case 0x0F:
switch (_cartInfo.CartridgeType)
{
switch(_cartInfo.CartridgeType) {
case 0x00:
_hasBattery = true;
_hasRtc = (_cartInfo.RomType & 0x0F) == 0x09;
@ -327,9 +271,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType()
}
break;
}
}
else if (GetGameCode() == "042J")
{
} else if(GetGameCode() == "042J") {
return CoprocessorType::SGB;
}
@ -339,8 +281,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType()
CoprocessorType BaseCartridge::GetSt01xVersion()
{
string cartName = GetCartName();
if (cartName == "2DAN MORITA SHOUGI")
{
if(cartName == "2DAN MORITA SHOUGI") {
return CoprocessorType::ST011;
}
@ -350,21 +291,14 @@ CoprocessorType BaseCartridge::GetSt01xVersion()
CoprocessorType BaseCartridge::GetDspVersion()
{
string cartName = GetCartName();
if (cartName == "DUNGEON MASTER")
{
if(cartName == "DUNGEON MASTER") {
return CoprocessorType::DSP2;
}
if (cartName == "PILOTWINGS")
{
} if(cartName == "PILOTWINGS") {
return CoprocessorType::DSP1;
}
else if (cartName == "SD\xB6\xDE\xDD\xC0\xDE\xD1GX")
{
} else if(cartName == "SD\xB6\xDE\xDD\xC0\xDE\xD1GX") {
//SD Gundam GX
return CoprocessorType::DSP3;
}
else if (cartName == "PLANETS CHAMP TG3000" || cartName == "TOP GEAR 3000")
{
} else if(cartName == "PLANETS CHAMP TG3000" || cartName == "TOP GEAR 3000") {
return CoprocessorType::DSP4;
}
@ -374,12 +308,10 @@ CoprocessorType BaseCartridge::GetDspVersion()
void BaseCartridge::Reset()
{
if (_coprocessor)
{
if(_coprocessor) {
_coprocessor->Reset();
}
if (_bsxMemPack)
{
if(_bsxMemPack) {
_bsxMemPack->Reset();
}
}
@ -398,43 +330,30 @@ RomInfo BaseCartridge::GetRomInfo()
vector<uint8_t> BaseCartridge::GetOriginalPrgRom()
{
RomInfo romInfo = GetRomInfo();
shared_ptr<BaseCartridge> originalCart =
BaseCartridge::CreateCartridge(_console, romInfo.RomFile, romInfo.PatchFile);
if (originalCart->_gameboy)
{
shared_ptr<BaseCartridge> originalCart = BaseCartridge::CreateCartridge(_console, romInfo.RomFile, romInfo.PatchFile);
if(originalCart->_gameboy) {
uint8_t* orgPrgRom = originalCart->_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom);
uint32_t orgRomSize = originalCart->_gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom);
return vector<uint8_t>(orgPrgRom, orgPrgRom + orgRomSize);
}
else
{
return vector<uint8_t>(originalCart->DebugGetPrgRom(),
originalCart->DebugGetPrgRom() + originalCart->DebugGetPrgRomSize());
} else {
return vector<uint8_t>(originalCart->DebugGetPrgRom(), originalCart->DebugGetPrgRom() + originalCart->DebugGetPrgRomSize());
}
}
uint32_t BaseCartridge::GetCrc32()
{
if (_gameboy)
{
return CRC32::GetCRC(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom),
_gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom));
}
else
{
if(_gameboy) {
return CRC32::GetCRC(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom));
} else {
return CRC32::GetCRC(_prgRom, _prgRomSize);
}
}
string BaseCartridge::GetSha1Hash()
{
if (_gameboy)
{
return SHA1::GetHash(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom),
_gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom));
}
else
{
if(_gameboy) {
return SHA1::GetHash(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom));
} else {
return SHA1::GetHash(_prgRom, _prgRomSize);
}
}
@ -446,122 +365,97 @@ CartFlags::CartFlags BaseCartridge::GetCartFlags()
void BaseCartridge::LoadBattery()
{
if (_saveRamSize > 0)
{
if(_saveRamSize > 0) {
_console->GetBatteryManager()->LoadBattery(".srm", _saveRam, _saveRamSize);
}
if (_coprocessor && _hasBattery)
{
if(_coprocessor && _hasBattery) {
_coprocessor->LoadBattery();
}
if (_gameboy)
{
if(_gameboy) {
_gameboy->LoadBattery();
}
}
void BaseCartridge::SaveBattery()
{
if (_saveRamSize > 0)
{
if(_saveRamSize > 0) {
_console->GetBatteryManager()->SaveBattery(".srm", _saveRam, _saveRamSize);
}
if (_coprocessor && _hasBattery)
{
if(_coprocessor && _hasBattery) {
_coprocessor->SaveBattery();
}
if (_bsxMemPack)
{
if(_bsxMemPack) {
_bsxMemPack->SaveBattery();
}
if (_gameboy)
{
if(_gameboy) {
_gameboy->SaveBattery();
}
}
void BaseCartridge::Init(MemoryMappings& mm)
void BaseCartridge::Init(MemoryMappings &mm)
{
_prgRomHandlers.clear();
_saveRamHandlers.clear();
for (uint32_t i = 0; i < _prgRomSize; i += 0x1000)
{
_prgRomHandlers.
push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom, i, _prgRomSize, SnesMemoryType::PrgRom)));
for(uint32_t i = 0; i < _prgRomSize; i += 0x1000) {
_prgRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom, i, _prgRomSize, SnesMemoryType::PrgRom)));
}
uint32_t power = (uint32_t)std::log2(_prgRomSize);
if (_prgRomSize > (1u << power))
{
if(_prgRomSize >(1u << power)) {
//If size isn't a power of 2, mirror the part above the nearest (lower) power of 2 until the size reaches the next power of 2.
uint32_t halfSize = 1 << power;
uint32_t fullSize = 1 << (power + 1);
uint32_t extraHandlers = std::max<uint32_t>((_prgRomSize - halfSize) / 0x1000, 1);
while (_prgRomHandlers.size() < fullSize / 0x1000)
{
for (uint32_t i = 0; i < extraHandlers; i += 0x1000)
{
_prgRomHandlers.push_back(
unique_ptr<RomHandler>(new RomHandler(_prgRom, halfSize + i, _prgRomSize, SnesMemoryType::PrgRom)));
while(_prgRomHandlers.size() < fullSize / 0x1000) {
for(uint32_t i = 0; i < extraHandlers; i += 0x1000) {
_prgRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom, halfSize + i, _prgRomSize, SnesMemoryType::PrgRom)));
}
}
}
for (uint32_t i = 0; i < _saveRamSize; i += 0x1000)
{
_saveRamHandlers.push_back(
unique_ptr<RamHandler>(new RamHandler(_saveRam, i, _saveRamSize, SnesMemoryType::SaveRam)));
for(uint32_t i = 0; i < _saveRamSize; i += 0x1000) {
_saveRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_saveRam, i, _saveRamSize, SnesMemoryType::SaveRam)));
}
RegisterHandlers(mm);
if (_coprocessorType != CoprocessorType::Gameboy)
{
if(_coprocessorType != CoprocessorType::Gameboy) {
InitCoprocessor();
}
LoadBattery();
}
void BaseCartridge::RegisterHandlers(MemoryMappings& mm)
void BaseCartridge::RegisterHandlers(MemoryMappings &mm)
{
if (MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1 ||
_coprocessorType == CoprocessorType::SPC7110 || _coprocessorType == CoprocessorType::CX4)
{
if(MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1 || _coprocessorType == CoprocessorType::SPC7110 || _coprocessorType == CoprocessorType::CX4) {
MapBsxMemoryPack(mm);
return;
}
if (_flags & CartFlags::LoRom)
{
if(_flags & CartFlags::LoRom) {
mm.RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, _prgRomHandlers);
mm.RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, _prgRomHandlers);
if (_saveRamSize > 0)
{
if (_prgRomSize >= 1024 * 1024 * 2)
{
if(_saveRamSize > 0) {
if(_prgRomSize >= 1024 * 1024 * 2) {
//For games >= 2mb in size, put ROM at 70-7D/F0-FF:0000-7FFF (e.g: Fire Emblem: Thracia 776)
mm.RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _saveRamHandlers);
mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers);
}
else
{
} else {
//For games < 2mb in size, put save RAM at 70-7D/F0-FF:0000-FFFF (e.g: Wanderers from Ys)
mm.RegisterHandler(0x70, 0x7D, 0x0000, 0xFFFF, _saveRamHandlers);
mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0xFFFF, _saveRamHandlers);
}
}
}
else if (_flags & CartFlags::HiRom)
{
} else if(_flags & CartFlags::HiRom) {
mm.RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, _prgRomHandlers, 8);
mm.RegisterHandler(0x40, 0x7D, 0x0000, 0xFFFF, _prgRomHandlers, 0);
mm.RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 8);
@ -569,9 +463,7 @@ void BaseCartridge::RegisterHandlers(MemoryMappings& mm)
mm.RegisterHandler(0x20, 0x3F, 0x6000, 0x7FFF, _saveRamHandlers);
mm.RegisterHandler(0xA0, 0xBF, 0x6000, 0x7FFF, _saveRamHandlers);
}
else if (_flags & CartFlags::ExHiRom)
{
} else if(_flags & CartFlags::ExHiRom) {
//First half is at the end
mm.RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, _prgRomHandlers, 0);
mm.RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 8); //mirror
@ -592,16 +484,11 @@ void BaseCartridge::RegisterHandlers(MemoryMappings& mm)
void BaseCartridge::LoadEmbeddedFirmware()
{
//Attempt to detect/load the firmware from the end of the rom file, if it exists
if ((_coprocessorType >= CoprocessorType::DSP1 && _coprocessorType <= CoprocessorType::DSP4) || (_coprocessorType >=
CoprocessorType::ST010 && _coprocessorType <= CoprocessorType::ST011))
{
if((_coprocessorType >= CoprocessorType::DSP1 && _coprocessorType <= CoprocessorType::DSP4) || (_coprocessorType >= CoprocessorType::ST010 && _coprocessorType <= CoprocessorType::ST011)) {
uint32_t firmwareSize = 0;
if ((_prgRomSize & 0x7FFF) == 0x2000)
{
if((_prgRomSize & 0x7FFF) == 0x2000) {
firmwareSize = 0x2000;
}
else if ((_prgRomSize & 0xFFFF) == 0xD000)
{
} else if((_prgRomSize & 0xFFFF) == 0xD000) {
firmwareSize = 0xD000;
}
@ -616,33 +503,23 @@ void BaseCartridge::InitCoprocessor()
_coprocessor.reset(NecDsp::InitCoprocessor(_coprocessorType, _console, _embeddedFirmware));
_necDsp = dynamic_cast<NecDsp*>(_coprocessor.get());
if (_coprocessorType == CoprocessorType::SA1)
{
if(_coprocessorType == CoprocessorType::SA1) {
_coprocessor.reset(new Sa1(_console));
_sa1 = dynamic_cast<Sa1*>(_coprocessor.get());
_needCoprocSync = true;
}
else if (_coprocessorType == CoprocessorType::GSU)
{
} else if(_coprocessorType == CoprocessorType::GSU) {
_coprocessor.reset(new Gsu(_console, _coprocessorRamSize));
_gsu = dynamic_cast<Gsu*>(_coprocessor.get());
_needCoprocSync = true;
}
else if (_coprocessorType == CoprocessorType::SDD1)
{
} else if(_coprocessorType == CoprocessorType::SDD1) {
_coprocessor.reset(new Sdd1(_console));
}
else if (_coprocessorType == CoprocessorType::SPC7110)
{
} else if(_coprocessorType == CoprocessorType::SPC7110) {
_coprocessor.reset(new Spc7110(_console, _hasRtc));
}
else if (_coprocessorType == CoprocessorType::Satellaview)
{
} else if(_coprocessorType == CoprocessorType::Satellaview) {
//Share save file across all .bs files that use the BS-X bios
_console->GetBatteryManager()->Initialize("BsxBios");
if (!_bsxMemPack)
{
if(!_bsxMemPack) {
//Create an empty memory pack if the BIOS was loaded directly (instead of a .bs file)
vector<uint8_t> emptyMemPack;
_bsxMemPack.reset(new BsxMemoryPack(_console, emptyMemPack, false));
@ -650,31 +527,24 @@ void BaseCartridge::InitCoprocessor()
_coprocessor.reset(new BsxCart(_console, _bsxMemPack.get()));
_bsx = dynamic_cast<BsxCart*>(_coprocessor.get());
}
else if (_coprocessorType == CoprocessorType::CX4)
{
} else if(_coprocessorType == CoprocessorType::CX4) {
_coprocessor.reset(new Cx4(_console));
_cx4 = dynamic_cast<Cx4*>(_coprocessor.get());
_needCoprocSync = true;
}
else if (_coprocessorType == CoprocessorType::OBC1 && _saveRamSize > 0)
{
} else if(_coprocessorType == CoprocessorType::OBC1 && _saveRamSize > 0) {
_coprocessor.reset(new Obc1(_console, _saveRam, _saveRamSize));
}
else if (_coprocessorType == CoprocessorType::SGB)
{
} else if(_coprocessorType == CoprocessorType::SGB) {
_coprocessor.reset(new SuperGameboy(_console));
_sgb = dynamic_cast<SuperGameboy*>(_coprocessor.get());
_needCoprocSync = true;
}
}
bool BaseCartridge::MapSpecificCarts(MemoryMappings& mm)
bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm)
{
string name = GetCartName();
string code = GetGameCode();
if (GetCartName() == "DEZAEMON")
{
if(GetCartName() == "DEZAEMON") {
//LOROM with mirrored SRAM?
mm.RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, _prgRomHandlers);
mm.RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, _prgRomHandlers);
@ -687,16 +557,13 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings& mm)
mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers);
return true;
}
else if (code == "ZDBJ" || code == "ZR2J" || code == "ZSNJ")
{
} else if(code == "ZDBJ" || code == "ZR2J" || code == "ZSNJ") {
//BSC-1A5M-02, BSC-1A7M-01
//Games: Sound Novel Tsukuuru, RPG Tsukuuru, Derby Stallion 96
mm.RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, _prgRomHandlers);
mm.RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, _prgRomHandlers, 0, 0x200);
mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 0, 0x100);
if (_saveRamSize > 0)
{
if(_saveRamSize > 0) {
mm.RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _saveRamHandlers);
mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers);
}
@ -708,24 +575,19 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings& mm)
void BaseCartridge::MapBsxMemoryPack(MemoryMappings& mm)
{
string code = GetGameCode();
if (!_bsxMemPack && code.size() == 4 && code[0] == 'Z' && _cartInfo.DeveloperId == 0x33)
{
if(!_bsxMemPack && code.size() == 4 && code[0] == 'Z' && _cartInfo.DeveloperId == 0x33) {
//Game with data pack slot (e.g Sound Novel Tsukuuru, etc.)
vector<uint8_t> saveData = _console->GetBatteryManager()->LoadBattery(".bs");
if (saveData.empty())
{
if(saveData.empty()) {
//Make a 1 megabyte flash cartridge by default (use $FF for all bytes)
saveData.resize(0x100000, 0xFF);
}
_bsxMemPack.reset(new BsxMemoryPack(_console, saveData, true));
if (_flags & CartFlags::LoRom)
{
if(_flags & CartFlags::LoRom) {
mm.RegisterHandler(0xC0, 0xEF, 0x0000, 0x7FFF, _bsxMemPack->GetMemoryHandlers());
mm.RegisterHandler(0xC0, 0xEF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers());
}
else
{
} else {
mm.RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8);
mm.RegisterHandler(0x60, 0x7D, 0x0000, 0xFFFF, _bsxMemPack->GetMemoryHandlers());
mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8);
@ -739,15 +601,12 @@ void BaseCartridge::MapBsxMemoryPack(MemoryMappings& mm)
void BaseCartridge::ApplyConfigOverrides()
{
string name = GetCartName();
if (name == "POWERDRIVE" || name == "DEATH BRADE" || name == "RPG SAILORMOON")
{
if(name == "POWERDRIVE" || name == "DEATH BRADE" || name == "RPG SAILORMOON") {
//These games work better when ram is initialized to $FF
EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig();
cfg.RamPowerOnState = RamState::AllOnes;
_console->GetSettings()->SetEmulationConfig(cfg);
}
else if (name == "SUPER KEIBA 2")
{
} else if(name == "SUPER KEIBA 2") {
//Super Keiba 2 behaves incorrectly if save ram is filled with 0s
EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig();
cfg.RamPowerOnState = RamState::Random;
@ -761,37 +620,29 @@ void BaseCartridge::LoadSpc()
SetupCpuHalt();
}
bool BaseCartridge::LoadGameboy(VirtualFile& romFile, bool sgbEnabled)
bool BaseCartridge::LoadGameboy(VirtualFile &romFile, bool sgbEnabled)
{
_gameboy.reset(Gameboy::Create(_console, romFile, sgbEnabled));
if (!_gameboy)
{
if(!_gameboy) {
return false;
}
_cartInfo = {};
_cartInfo = { };
_headerOffset = Gameboy::HeaderOffset;
if (_gameboy->IsSgb())
{
if(_gameboy->IsSgb()) {
GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig();
if (FirmwareHelper::LoadSgbFirmware(_console, &_prgRom, _prgRomSize, cfg.UseSgb2))
{
if(FirmwareHelper::LoadSgbFirmware(_console, &_prgRom, _prgRomSize, cfg.UseSgb2)) {
LoadRom();
if (_coprocessorType != CoprocessorType::SGB)
{
if(_coprocessorType != CoprocessorType::SGB) {
//SGB bios file isn't a recognized SGB bios, try again without SGB mode
return LoadGameboy(romFile, false);
}
}
else
{
} else {
//Couldn't load the SGB bios, try again with in GB/GBC mode
return LoadGameboy(romFile, false);
}
}
else
{
} else {
_coprocessorType = CoprocessorType::Gameboy;
SetupCpuHalt();
}
@ -819,19 +670,16 @@ void BaseCartridge::SetupCpuHalt()
_prgRom[3] = 0x00;
}
void BaseCartridge::Serialize(Serializer& s)
void BaseCartridge::Serialize(Serializer &s)
{
s.StreamArray(_saveRam, _saveRamSize);
if (_coprocessor)
{
if(_coprocessor) {
s.Stream(_coprocessor.get());
}
if (_bsxMemPack)
{
if(_bsxMemPack) {
s.Stream(_bsxMemPack.get());
}
if (_gameboy)
{
if(_gameboy) {
s.Stream(_gameboy.get());
}
}
@ -839,20 +687,16 @@ void BaseCartridge::Serialize(Serializer& s)
string BaseCartridge::GetGameCode()
{
string code;
if (_cartInfo.GameCode[0] > ' ')
{
if(_cartInfo.GameCode[0] > ' ') {
code += _cartInfo.GameCode[0];
}
if (_cartInfo.GameCode[1] > ' ')
{
if(_cartInfo.GameCode[1] > ' ') {
code += _cartInfo.GameCode[1];
}
if (_cartInfo.GameCode[2] > ' ')
{
if(_cartInfo.GameCode[2] > ' ') {
code += _cartInfo.GameCode[2];
}
if (_cartInfo.GameCode[3] > ' ')
{
if(_cartInfo.GameCode[3] > ' ') {
code += _cartInfo.GameCode[3];
}
return code;
@ -861,10 +705,8 @@ string BaseCartridge::GetGameCode()
string BaseCartridge::GetCartName()
{
int nameLength = 21;
for (int i = 0; i < 21; i++)
{
if (_cartInfo.CartName[i] == 0)
{
for(int i = 0; i < 21; i++) {
if(_cartInfo.CartName[i] == 0) {
nameLength = i;
break;
}
@ -872,12 +714,9 @@ string BaseCartridge::GetCartName()
string name = string(_cartInfo.CartName, nameLength);
size_t lastNonSpace = name.find_last_not_of(' ');
if (lastNonSpace != string::npos)
{
if(lastNonSpace != string::npos) {
return name.substr(0, lastNonSpace + 1);
}
else
{
} else {
return name;
}
}
@ -885,8 +724,7 @@ string BaseCartridge::GetCartName()
ConsoleRegion BaseCartridge::GetRegion()
{
uint8_t destCode = _cartInfo.DestinationCode;
if ((destCode >= 0x02 && destCode <= 0x0C) || destCode == 0x11 || destCode == 0x12)
{
if((destCode >= 0x02 && destCode <= 0x0C) || destCode == 0x11 || destCode == 0x12) {
return ConsoleRegion::Pal;
}
return ConsoleRegion::Ntsc;
@ -898,81 +736,50 @@ void BaseCartridge::DisplayCartInfo()
MessageManager::Log("File: " + VirtualFile(_romPath).GetFileName());
MessageManager::Log("Game: " + GetCartName());
string gameCode = GetGameCode();
if (!gameCode.empty())
{
if(!gameCode.empty()) {
MessageManager::Log("Game code: " + gameCode);
}
if (_flags & CartFlags::ExHiRom)
{
if(_flags & CartFlags::ExHiRom) {
MessageManager::Log("Type: ExHiROM");
}
else if (_flags & CartFlags::ExLoRom)
{
} else if(_flags & CartFlags::ExLoRom) {
MessageManager::Log("Type: ExLoROM");
}
else if (_flags & CartFlags::HiRom)
{
} else if(_flags & CartFlags::HiRom) {
MessageManager::Log("Type: HiROM");
}
else if (_flags & CartFlags::LoRom)
{
} else if(_flags & CartFlags::LoRom) {
MessageManager::Log("Type: LoROM");
}
if (_coprocessorType != CoprocessorType::None)
{
if(_coprocessorType != CoprocessorType::None) {
string coProcMessage = "Coprocessor: ";
switch (_coprocessorType)
{
case CoprocessorType::None: coProcMessage += "<none>";
break;
case CoprocessorType::CX4: coProcMessage += "CX4";
break;
case CoprocessorType::SDD1: coProcMessage += "S-DD1";
break;
case CoprocessorType::DSP1: coProcMessage += "DSP1";
break;
case CoprocessorType::DSP1B: coProcMessage += "DSP1B";
break;
case CoprocessorType::DSP2: coProcMessage += "DSP2";
break;
case CoprocessorType::DSP3: coProcMessage += "DSP3";
break;
case CoprocessorType::DSP4: coProcMessage += "DSP4";
break;
case CoprocessorType::GSU: coProcMessage += "Super FX (GSU1/2)";
break;
case CoprocessorType::OBC1: coProcMessage += "OBC1";
break;
case CoprocessorType::RTC: coProcMessage += "RTC";
break;
case CoprocessorType::SA1: coProcMessage += "SA1";
break;
case CoprocessorType::Satellaview: coProcMessage += "Satellaview";
break;
case CoprocessorType::SPC7110: coProcMessage += "SPC7110";
break;
case CoprocessorType::ST010: coProcMessage += "ST010";
break;
case CoprocessorType::ST011: coProcMessage += "ST011";
break;
case CoprocessorType::ST018: coProcMessage += "ST018";
break;
case CoprocessorType::Gameboy: coProcMessage += "Game Boy";
break;
case CoprocessorType::SGB: coProcMessage += "Super Game Boy";
break;
switch(_coprocessorType) {
case CoprocessorType::None: coProcMessage += "<none>"; break;
case CoprocessorType::CX4: coProcMessage += "CX4"; break;
case CoprocessorType::SDD1: coProcMessage += "S-DD1"; break;
case CoprocessorType::DSP1: coProcMessage += "DSP1"; break;
case CoprocessorType::DSP1B: coProcMessage += "DSP1B"; break;
case CoprocessorType::DSP2: coProcMessage += "DSP2"; break;
case CoprocessorType::DSP3: coProcMessage += "DSP3"; break;
case CoprocessorType::DSP4: coProcMessage += "DSP4"; break;
case CoprocessorType::GSU: coProcMessage += "Super FX (GSU1/2)"; break;
case CoprocessorType::OBC1: coProcMessage += "OBC1"; break;
case CoprocessorType::RTC: coProcMessage += "RTC"; break;
case CoprocessorType::SA1: coProcMessage += "SA1"; break;
case CoprocessorType::Satellaview: coProcMessage += "Satellaview"; break;
case CoprocessorType::SPC7110: coProcMessage += "SPC7110"; break;
case CoprocessorType::ST010: coProcMessage += "ST010"; break;
case CoprocessorType::ST011: coProcMessage += "ST011"; break;
case CoprocessorType::ST018: coProcMessage += "ST018"; break;
case CoprocessorType::Gameboy: coProcMessage += "Game Boy"; break;
case CoprocessorType::SGB: coProcMessage += "Super Game Boy"; break;
}
MessageManager::Log(coProcMessage);
}
if (_flags & CartFlags::FastRom)
{
if(_flags & CartFlags::FastRom) {
MessageManager::Log("FastROM");
}
if (_flags & CartFlags::CopierHeader)
{
if(_flags & CartFlags::CopierHeader) {
MessageManager::Log("Copier header found.");
}
@ -981,17 +788,13 @@ void BaseCartridge::DisplayCartInfo()
MessageManager::Log("File size: " + std::to_string(_prgRomSize / 1024) + " KB");
MessageManager::Log("ROM size: " + std::to_string((0x400 << _cartInfo.RomSize) / 1024) + " KB");
if (_saveRamSize > 0)
{
MessageManager::Log(
"SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB" + (_hasBattery ? " (with battery)" : ""));
if(_saveRamSize > 0) {
MessageManager::Log("SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB" + (_hasBattery ? " (with battery)" : ""));
}
if (_coprocessorRamSize > 0)
{
if(_coprocessorRamSize > 0) {
MessageManager::Log("Coprocessor RAM size: " + std::to_string(_coprocessorRamSize / 1024) + " KB");
}
if (_hasBattery)
{
if(_hasBattery) {
MessageManager::Log("Battery: yes");
}
MessageManager::Log("-----------------------------");
@ -1040,8 +843,7 @@ Gameboy* BaseCartridge::GetGameboy()
void BaseCartridge::RunCoprocessors()
{
//These coprocessors are run at the end of the frame, or as needed
if (_necDsp)
{
if(_necDsp) {
_necDsp->Run();
}
}

View file

@ -23,7 +23,7 @@ enum class ConsoleRegion;
class BaseCartridge : public ISerializable
{
private:
Console* _console;
Console *_console;
vector<unique_ptr<IMemoryHandler>> _prgRomHandlers;
vector<unique_ptr<IMemoryHandler>> _saveRamHandlers;
@ -33,11 +33,11 @@ private:
bool _needCoprocSync = false;
unique_ptr<BaseCoprocessor> _coprocessor;
NecDsp* _necDsp = nullptr;
Sa1* _sa1 = nullptr;
Gsu* _gsu = nullptr;
Cx4* _cx4 = nullptr;
SuperGameboy* _sgb = nullptr;
NecDsp *_necDsp = nullptr;
Sa1 *_sa1 = nullptr;
Gsu *_gsu = nullptr;
Cx4 *_cx4 = nullptr;
SuperGameboy *_sgb = nullptr;
BsxCart* _bsx = nullptr;
unique_ptr<BsxMemoryPack> _bsxMemPack;
unique_ptr<Gameboy> _gameboy;
@ -85,13 +85,13 @@ private:
public:
virtual ~BaseCartridge();
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile);
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile);
void Reset();
void SaveBattery();
void Init(MemoryMappings& mm);
void Init(MemoryMappings &mm);
RomInfo GetRomInfo();
vector<uint8_t> GetOriginalPrgRom();
@ -100,7 +100,7 @@ public:
string GetSha1Hash();
CartFlags::CartFlags GetCartFlags();
void RegisterHandlers(MemoryMappings& mm);
void RegisterHandlers(MemoryMappings &mm);
uint8_t* DebugGetPrgRom() { return _prgRom; }
uint8_t* DebugGetSaveRam() { return _saveRam; }
@ -120,8 +120,7 @@ public:
__forceinline void SyncCoprocessors()
{
if (_needCoprocSync)
{
if(_needCoprocSync) {
_coprocessor->Run();
}
}
@ -133,5 +132,5 @@ public:
SpcFileData* GetSpcData();
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

@ -44,8 +44,7 @@ bool BaseControlDevice::IsExpansionDevice()
void BaseControlDevice::StrobeProcessRead()
{
if (_strobe)
{
if(_strobe) {
RefreshStateBuffer();
}
}
@ -55,8 +54,7 @@ void BaseControlDevice::StrobeProcessWrite(uint8_t value)
bool prevStrobe = _strobe;
_strobe = (value & 0x01) == 0x01;
if (prevStrobe && !_strobe)
{
if(prevStrobe && !_strobe) {
RefreshStateBuffer();
}
}
@ -84,25 +82,17 @@ void BaseControlDevice::SetTextState(string textState)
auto lock = _stateLock.AcquireSafe();
ClearState();
if (IsRawString())
{
if(IsRawString()) {
_state.State.insert(_state.State.end(), textState.begin(), textState.end());
}
else
{
if (HasCoordinates())
{
} else {
if(HasCoordinates()) {
vector<string> data = StringUtilities::Split(textState, ' ');
if (data.size() >= 3)
{
if(data.size() >= 3) {
MousePosition pos;
try
{
try {
pos.X = (int16_t)std::stol(data[0]);
pos.Y = (int16_t)std::stol(data[1]);
}
catch (std::exception&)
{
} catch(std::exception&) {
pos.X = -1;
pos.Y = -1;
}
@ -112,13 +102,10 @@ void BaseControlDevice::SetTextState(string textState)
}
int i = 0;
for (char c : textState)
{
if (c != ':')
{
for(char c : textState) {
if(c != ':') {
//Ignore colons (used by multitap to separate inputs)
if (c != '.')
{
if(c != '.') {
SetBit(i);
}
i++;
@ -130,32 +117,24 @@ void BaseControlDevice::SetTextState(string textState)
string BaseControlDevice::GetTextState()
{
auto lock = _stateLock.AcquireSafe();
if (IsRawString())
{
if(IsRawString()) {
return string((char*)_state.State.data(), _state.State.size());
}
else
{
} else {
string keyNames = GetKeyNames();
string output = "";
if (HasCoordinates())
{
if(HasCoordinates()) {
MousePosition pos = GetCoordinates();
output += std::to_string(pos.X) + " " + std::to_string(pos.Y) + " ";
}
int keyNumber = 0;
for (size_t i = 0; i < keyNames.size(); i++)
{
if (keyNames[i] != ':')
{
for(size_t i = 0; i < keyNames.size(); i++) {
if(keyNames[i] != ':') {
//Ignore colons in string (used by multitap to split controllers)
output += IsPressed((uint8_t)keyNumber) ? keyNames[i] : '.';
keyNumber++;
}
else
{
} else {
output += ':';
}
}
@ -170,8 +149,7 @@ void BaseControlDevice::EnsureCapacity(int32_t minBitCount)
uint32_t minByteCount = minBitCount / 8 + 1 + (HasCoordinates() ? 32 : 0);
int32_t gap = minByteCount - (int32_t)_state.State.size();
if (gap > 0)
{
if(gap > 0) {
_state.State.insert(_state.State.end(), gap, 0);
}
}
@ -201,12 +179,9 @@ bool BaseControlDevice::IsPressed(uint8_t bit)
void BaseControlDevice::SetBitValue(uint8_t bit, bool set)
{
if (set)
{
if(set) {
SetBit(bit);
}
else
{
} else {
ClearBit(bit);
}
}
@ -229,28 +204,23 @@ void BaseControlDevice::ClearBit(uint8_t bit)
void BaseControlDevice::InvertBit(uint8_t bit)
{
if (IsPressed(bit))
{
if(IsPressed(bit)) {
ClearBit(bit);
}
else
{
} else {
SetBit(bit);
}
}
void BaseControlDevice::SetPressedState(uint8_t bit, uint32_t keyCode)
{
if (KeyManager::IsKeyPressed(keyCode))
{
if(KeyManager::IsKeyPressed(keyCode)) {
SetBit(bit);
}
}
void BaseControlDevice::SetPressedState(uint8_t bit, bool enabled)
{
if (enabled)
{
if(enabled) {
SetBit(bit);
}
}
@ -282,18 +252,17 @@ void BaseControlDevice::SetMovement(MouseMovement mov)
MouseMovement prev = GetMovement();
mov.dx += prev.dx;
mov.dy += prev.dy;
SetCoordinates({mov.dx, mov.dy});
SetCoordinates({ mov.dx, mov.dy });
}
MouseMovement BaseControlDevice::GetMovement()
{
MousePosition pos = GetCoordinates();
SetCoordinates({0, 0});
return {pos.X, pos.Y};
SetCoordinates({ 0, 0 });
return { pos.X, pos.Y };
}
void BaseControlDevice::SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1,
shared_ptr<BaseControlDevice> state2, uint8_t button2)
void BaseControlDevice::SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2, uint8_t button2)
{
bool pressed1 = state1->IsPressed(button1);
bool pressed2 = state2->IsPressed(button2);
@ -301,17 +270,15 @@ void BaseControlDevice::SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_
state1->ClearBit(button1);
state2->ClearBit(button2);
if (pressed1)
{
if(pressed1) {
state2->SetBit(button2);
}
if (pressed2)
{
if(pressed2) {
state1->SetBit(button1);
}
}
void BaseControlDevice::Serialize(Serializer& s)
void BaseControlDevice::Serialize(Serializer &s)
{
auto lock = _stateLock.AcquireSafe();
s.Stream(_strobe);

View file

@ -20,9 +20,7 @@ protected:
uint8_t _port;
SimpleLock _stateLock;
virtual void RefreshStateBuffer()
{
}
virtual void RefreshStateBuffer() { }
void EnsureCapacity(int32_t minBitCount);
uint32_t GetByteIndex(uint8_t bit);
@ -71,10 +69,7 @@ public:
string GetTextState();
void SetStateFromInput();
virtual void OnAfterSetState()
{
}
virtual void OnAfterSetState() { }
void SetRawState(ControlDeviceState state);
ControlDeviceState GetRawState();
@ -83,8 +78,7 @@ public:
virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0;
void static SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2,
uint8_t button2);
void static SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2, uint8_t button2);
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

@ -10,19 +10,8 @@ public:
virtual void Reset() = 0;
virtual void Run()
{
}
virtual void ProcessEndOfFrame()
{
}
virtual void LoadBattery()
{
}
virtual void SaveBattery()
{
}
virtual void Run() { }
virtual void ProcessEndOfFrame() { }
virtual void LoadBattery() { }
virtual void SaveBattery() { }
};

View file

@ -9,8 +9,7 @@ BaseRenderer::BaseRenderer(shared_ptr<Console> console, bool registerAsMessageMa
{
_console = console;
if (registerAsMessageManager)
{
if(registerAsMessageManager) {
//Only display messages on the master CPU's screen
MessageManager::RegisterMessageManager(this);
}
@ -38,44 +37,34 @@ void BaseRenderer::DrawToasts()
int counter = 0;
int lastHeight = 5;
for (shared_ptr<ToastInfo> toast : _toasts)
{
if (counter < 6)
{
for(shared_ptr<ToastInfo> toast : _toasts) {
if(counter < 6) {
DrawToast(toast, lastHeight);
}
else
{
} else {
break;
}
counter++;
}
}
std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t& lineCount)
std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount)
{
using std::wstring;
wstring text = utf8::utf8::decode(utf8Text);
wstring wrappedText;
list<wstring> words;
wstring currentWord;
for (size_t i = 0, len = text.length(); i < len; i++)
{
if (text[i] == L' ' || text[i] == L'\n')
{
if (currentWord.length() > 0)
{
for(size_t i = 0, len = text.length(); i < len; i++) {
if(text[i] == L' ' || text[i] == L'\n') {
if(currentWord.length() > 0) {
words.push_back(currentWord);
currentWord.clear();
}
}
else
{
} else {
currentWord += text[i];
}
}
if (currentWord.length() > 0)
{
if(currentWord.length() > 0) {
words.push_back(currentWord);
}
@ -83,25 +72,19 @@ std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_
float spaceWidth = MeasureString(L" ");
float lineWidth = 0.0f;
for (wstring word : words)
{
for (unsigned int i = 0; i < word.size(); i++)
{
if (!ContainsCharacter(word[i]))
{
for(wstring word : words) {
for(unsigned int i = 0; i < word.size(); i++) {
if(!ContainsCharacter(word[i])) {
word[i] = L'?';
}
}
float wordWidth = MeasureString(word.c_str());
if (lineWidth + wordWidth < maxLineWidth)
{
if(lineWidth + wordWidth < maxLineWidth) {
wrappedText += word + L" ";
lineWidth += wordWidth + spaceWidth;
}
else
{
} else {
wrappedText += L"\n" + word + L" ";
lineWidth = wordWidth + spaceWidth;
lineCount++;
@ -111,10 +94,10 @@ std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_
return wrappedText;
}
void BaseRenderer::DrawToast(shared_ptr<ToastInfo> toast, int& lastHeight)
void BaseRenderer::DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight)
{
//Get opacity for fade in/out effect
uint8_t opacity = (uint8_t)(toast->GetOpacity() * 255);
uint8_t opacity = (uint8_t)(toast->GetOpacity()*255);
int textLeftMargin = 4;
int lineHeight = 25;
@ -134,31 +117,24 @@ void BaseRenderer::DrawString(std::string message, int x, int y, uint8_t r, uint
void BaseRenderer::ShowFpsCounter(int lineNumber)
{
int yPos = 13 + 24 * lineNumber;
if (_fpsTimer.GetElapsedMS() > 1000)
{
if(_fpsTimer.GetElapsedMS() > 1000) {
//Update fps every sec
uint32_t frameCount = _console->GetFrameCount();
if (_lastFrameCount > frameCount)
{
if(_lastFrameCount > frameCount) {
_currentFPS = 0;
}
else
{
} else {
_currentFPS = (int)(std::round((double)(frameCount - _lastFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
_currentRenderedFPS = (int)(std::round(
(double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
_currentRenderedFPS = (int)(std::round((double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
}
_lastFrameCount = frameCount;
_lastRenderedFrameCount = _renderedFrameCount;
_fpsTimer.Reset();
}
if (_currentFPS > 5000)
{
if(_currentFPS > 5000) {
_currentFPS = 0;
}
if (_currentRenderedFPS > 5000)
{
if(_currentRenderedFPS > 5000) {
_currentRenderedFPS = 0;
}
@ -195,16 +171,13 @@ void BaseRenderer::DrawCounters()
{
int lineNumber = 0;
PreferencesConfig cfg = _console->GetSettings()->GetPreferences();
if (cfg.ShowGameTimer)
{
if(cfg.ShowGameTimer) {
ShowGameTimer(lineNumber++);
}
if (cfg.ShowFps)
{
if(cfg.ShowFps) {
ShowFpsCounter(lineNumber++);
}
if (cfg.ShowFrameCounter)
{
if(cfg.ShowFrameCounter) {
ShowFrameCounter(lineNumber++);
}
}

View file

@ -17,7 +17,7 @@ private:
uint32_t _currentRenderedFPS = 0;
void RemoveOldToasts();
std::wstring WrapText(string utf8Text, float maxLineWidth, uint32_t& lineCount);
std::wstring WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount);
virtual float MeasureString(std::wstring text) = 0;
virtual bool ContainsCharacter(wchar_t character) = 0;
@ -36,10 +36,9 @@ protected:
void DisplayMessage(string title, string message);
void DrawToasts();
void DrawToast(shared_ptr<ToastInfo> toast, int& lastHeight);
void DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight);
void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255);
virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255,
uint8_t opacity = 255) = 0;
virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255) = 0;
void ShowFpsCounter(int lineNumber);
void ShowLagCounter(int lineNumber);

View file

@ -5,31 +5,25 @@ void BaseSoundManager::ProcessLatency(uint32_t readPosition, uint32_t writePosit
{
//Record latency between read & write cursors once per frame
int32_t cursorGap;
if (writePosition < readPosition)
{
if(writePosition < readPosition) {
cursorGap = writePosition - readPosition + _bufferSize;
}
else
{
} else {
cursorGap = writePosition - readPosition;
}
_cursorGaps[_cursorGapIndex] = cursorGap;
_cursorGapIndex = (_cursorGapIndex + 1) % 60;
if (_cursorGapIndex == 0)
{
if(_cursorGapIndex == 0) {
_cursorGapFilled = true;
}
if (_cursorGapFilled)
{
if(_cursorGapFilled) {
//Once we have 60+ frames worth of data to work with, adjust playback frequency by +/- 0.5%
//To speed up or slow down playback in order to reach our latency goal.
uint32_t bytesPerSample = _isStereo ? 4 : 2;
int32_t gapSum = 0;
for (int i = 0; i < 60; i++)
{
for(int i = 0; i < 60; i++) {
gapSum += _cursorGaps[i];
}
int32_t gapAverage = gapSum / 60;

View file

@ -36,9 +36,8 @@ FrameInfo BaseVideoFilter::GetFrameInfo()
void BaseVideoFilter::UpdateBufferSize()
{
uint32_t newBufferSize = GetFrameInfo().Width * GetFrameInfo().Height;
if (_bufferSize != newBufferSize)
{
uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height;
if(_bufferSize != newBufferSize) {
_frameLock.Acquire();
delete[] _outputBuffer;
_bufferSize = newBufferSize;
@ -66,7 +65,7 @@ uint32_t BaseVideoFilter::GetBufferSize()
return _bufferSize * sizeof(uint32_t);
}
void BaseVideoFilter::SendFrame(uint16_t* ppuOutputBuffer, uint32_t frameNumber)
void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
{
_frameLock.Acquire();
_overscan = _console->GetSettings()->GetOverscan();
@ -92,15 +91,14 @@ uint32_t BaseVideoFilter::ApplyScanlineEffect(uint32_t argb, uint8_t scanlineInt
return 0xFF000000 | (r << 16) | (g << 8) | b;
}
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream* stream)
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream)
{
uint32_t* pngBuffer;
FrameInfo frameInfo;
uint32_t* frameBuffer = nullptr;
{
auto lock = _frameLock.AcquireSafe();
if (_bufferSize == 0 || !GetOutputBuffer())
{
if(_bufferSize == 0 || !GetOutputBuffer()) {
return;
}
@ -112,19 +110,14 @@ void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename
pngBuffer = frameBuffer;
shared_ptr<ScaleFilter> scaleFilter = ScaleFilter::GetScaleFilter(filterType);
if (scaleFilter)
{
pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height,
_console->GetSettings()->GetVideoConfig().ScanlineIntensity);
if(scaleFilter) {
pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetVideoConfig().ScanlineIntensity);
frameInfo = scaleFilter->GetFrameInfo(frameInfo);
}
if (!filename.empty())
{
if(!filename.empty()) {
PNGHelper::WritePNG(filename, pngBuffer, frameInfo.Width, frameInfo.Height);
}
else
{
} else {
PNGHelper::WritePNG(*stream, pngBuffer, frameInfo.Width, frameInfo.Height);
}
@ -138,21 +131,16 @@ void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType)
int counter = 0;
string baseFilename = FolderUtilities::CombinePath(FolderUtilities::GetScreenshotFolder(), romFilename);
string ssFilename;
while (true)
{
while(true) {
string counterStr = std::to_string(counter);
while (counterStr.length() < 3)
{
while(counterStr.length() < 3) {
counterStr = "0" + counterStr;
}
ssFilename = baseFilename + "_" + counterStr + ".png";
ifstream file(ssFilename, ios::in);
if (file)
{
if(file) {
file.close();
}
else
{
} else {
break;
}
counter++;
@ -162,3 +150,4 @@ void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType)
MessageManager::DisplayMessage("ScreenshotSaved", FolderUtilities::GetFilename(ssFilename, true));
}

View file

@ -20,7 +20,7 @@ protected:
shared_ptr<Console> _console;
FrameInfo _baseFrameInfo;
virtual void ApplyFilter(uint16_t* ppuOutputBuffer) = 0;
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
virtual void OnBeforeApplyFilter();
bool IsOddFrame();
uint32_t GetBufferSize();
@ -31,9 +31,9 @@ public:
virtual ~BaseVideoFilter();
uint32_t* GetOutputBuffer();
void SendFrame(uint16_t* ppuOutputBuffer, uint32_t frameNumber);
void SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
void TakeScreenshot(string romName, VideoFilterType filterType);
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream* stream = nullptr);
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr);
virtual OverscanDimensions GetOverscan();

View file

@ -31,8 +31,7 @@ void BatteryManager::SetBatteryRecorder(shared_ptr<IBatteryRecorder> recorder)
void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t length)
{
if (_saveEnabled)
{
if (_saveEnabled) {
#ifdef LIBRETRO
if (extension == ".srm") {
//Disable .srm files for libretro, let the frontend handle save ram
@ -41,8 +40,7 @@ void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t lengt
#endif
ofstream out(GetBasePath() + extension, ios::binary);
if (out)
{
if (out) {
out.write((char*)data, length);
}
}
@ -53,25 +51,19 @@ vector<uint8_t> BatteryManager::LoadBattery(string extension)
shared_ptr<IBatteryProvider> provider = _provider.lock();
vector<uint8_t> batteryData;
if (provider)
{
if(provider) {
//Used by movie player to provider initial state of ram at startup
batteryData = provider->LoadBattery(extension);
}
else
{
} else {
VirtualFile file = GetBasePath() + extension;
if (file.IsValid())
{
if(file.IsValid()) {
file.ReadFile(batteryData);
}
}
if (!batteryData.empty())
{
if(!batteryData.empty()) {
shared_ptr<IBatteryRecorder> recorder = _recorder.lock();
if (recorder)
{
if(recorder) {
//Used by movies to record initial state of battery-backed ram at power on
recorder->OnLoadBattery(extension, batteryData);
}

View file

@ -3,35 +3,22 @@
#include "DebugTypes.h"
#include "DebugUtilities.h"
bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo& info)
bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info)
{
if (memoryType <= DebugUtilities::GetLastCpuMemoryType() && !DebugUtilities::IsPpuMemory(info.Type))
{
if (startAddr == -1)
{
if(memoryType <= DebugUtilities::GetLastCpuMemoryType() && !DebugUtilities::IsPpuMemory(info.Type)) {
if(startAddr == -1) {
return true;
}
else if (endAddr == -1)
{
} else if(endAddr == -1) {
return (int32_t)memoryAddr == startAddr;
}
else
{
} else {
return (int32_t)memoryAddr >= startAddr && (int32_t)memoryAddr <= endAddr;
}
}
else if (memoryType == info.Type)
{
if (startAddr == -1)
{
} else if(memoryType == info.Type) {
if(startAddr == -1) {
return true;
}
else if (endAddr == -1)
{
} else if(endAddr == -1) {
return info.Address == startAddr;
}
else
{
} else {
return info.Address >= startAddr && info.Address <= endAddr;
}
}
@ -41,8 +28,7 @@ bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo& info)
bool Breakpoint::HasBreakpointType(BreakpointType bpType)
{
switch (bpType)
{
switch(bpType) {
default:
case BreakpointType::Execute: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Execute) != 0;
case BreakpointType::Read: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Read) != 0;

View file

@ -11,7 +11,7 @@ enum class BreakpointCategory;
class Breakpoint
{
public:
bool Matches(uint32_t memoryAddr, AddressInfo& info);
bool Matches(uint32_t memoryAddr, AddressInfo &info);
bool HasBreakpointType(BreakpointType bpType);
string GetCondition();
bool HasCondition();

View file

@ -7,7 +7,7 @@
#include "ExpressionEvaluator.h"
#include "EventManager.h"
BreakpointManager::BreakpointManager(Debugger* debugger, CpuType cpuType, IEventManager* eventManager)
BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager)
{
_debugger = debugger;
_cpuType = cpuType;
@ -18,8 +18,7 @@ BreakpointManager::BreakpointManager(Debugger* debugger, CpuType cpuType, IEvent
void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count)
{
_hasBreakpoint = false;
for (int i = 0; i < BreakpointManager::BreakpointTypeCount; i++)
{
for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) {
_breakpoints[i].clear();
_rpnList[i].clear();
_hasBreakpointType[i] = false;
@ -27,31 +26,24 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count)
_bpExpEval.reset(new ExpressionEvaluator(_debugger, _cpuType));
for (uint32_t j = 0; j < count; j++)
{
Breakpoint& bp = breakpoints[j];
for (int i = 0; i < BreakpointManager::BreakpointTypeCount; i++)
{
for(uint32_t j = 0; j < count; j++) {
Breakpoint &bp = breakpoints[j];
for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) {
BreakpointType bpType = (BreakpointType)i;
if ((bp.IsMarked() || bp.IsEnabled()) && bp.HasBreakpointType(bpType))
{
if((bp.IsMarked() || bp.IsEnabled()) && bp.HasBreakpointType(bpType)) {
CpuType cpuType = bp.GetCpuType();
if (_cpuType != cpuType)
{
if(_cpuType != cpuType) {
continue;
}
int curIndex = _breakpoints[i].size();
_breakpoints[i].insert(std::make_pair(curIndex, bp));
if (bp.HasCondition())
{
if(bp.HasCondition()) {
bool success = true;
ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success);
_rpnList[i].insert(std::make_pair(curIndex, success ? data : ExpressionData()));
}
else
{
} else {
_rpnList[i].insert(std::make_pair(curIndex, ExpressionData()));
}
@ -68,35 +60,27 @@ void BreakpointManager::GetBreakpoints(Breakpoint* breakpoints, int& execs, int&
reads = _breakpoints[static_cast<int>(BreakpointType::Read)].size();
writes = _breakpoints[static_cast<int>(BreakpointType::Write)].size();
if (breakpoints == NULL)
{
if (breakpoints == NULL) {
return;
}
int offset = 0;
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast<int>(
BreakpointType::Execute)].cend(); it++)
{
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast<int>(BreakpointType::Execute)].cend(); it++) {
breakpoints[offset++] = it->second;
}
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast<int>(
BreakpointType::Read)].cend(); it++)
{
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast<int>(BreakpointType::Read)].cend(); it++) {
breakpoints[offset++] = it->second;
}
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast<int>(
BreakpointType::Write)].cend(); it++)
{
for (auto it = _breakpoints[static_cast<int>(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast<int>(BreakpointType::Write)].cend(); it++) {
breakpoints[offset++] = it->second;
}
}
BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type)
{
switch (type)
{
switch(type) {
default:
case MemoryOperationType::ExecOperand:
case MemoryOperationType::ExecOpCode:
@ -112,32 +96,25 @@ BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type)
}
}
int BreakpointManager::InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address)
int BreakpointManager::InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address)
{
BreakpointType type = GetBreakpointType(operationInfo.Type);
if (!_hasBreakpointType[(int)type])
{
if(!_hasBreakpointType[(int)type]) {
return -1;
}
DebugState state;
_debugger->GetState(state, false);
EvalResultType resultType;
unordered_map<int, Breakpoint>& breakpoints = _breakpoints[(int)type];
for (auto it = breakpoints.begin(); it != breakpoints.end(); it++)
{
if (it->second.Matches(operationInfo.Address, address))
{
if (!it->second.HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)type][it->first], state, resultType,
operationInfo))
{
if (it->second.IsMarked())
{
unordered_map<int, Breakpoint> &breakpoints = _breakpoints[(int)type];
for (auto it = breakpoints.begin(); it != breakpoints.end(); it++) {
if (it->second.Matches(operationInfo.Address, address)) {
if (!it->second.HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)type][it->first], state, resultType, operationInfo)) {
if (it->second.IsMarked()) {
_eventManager->AddEvent(DebugEventType::Breakpoint, operationInfo, it->first);
}
if (it->second.IsEnabled())
{
if (it->second.IsEnabled()) {
return it->first;
}
}

View file

@ -16,9 +16,9 @@ class BreakpointManager
private:
static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec
Debugger* _debugger;
Debugger *_debugger;
CpuType _cpuType;
IEventManager* _eventManager;
IEventManager *_eventManager;
unordered_map<int, Breakpoint> _breakpoints[BreakpointTypeCount];
unordered_map<int, ExpressionData> _rpnList[BreakpointTypeCount];
@ -28,20 +28,19 @@ private:
unique_ptr<ExpressionEvaluator> _bpExpEval;
BreakpointType GetBreakpointType(MemoryOperationType type);
int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address);
int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address);
public:
BreakpointManager(Debugger* debugger, CpuType cpuType, IEventManager* eventManager = nullptr);
BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager = nullptr);
void SetBreakpoints(Breakpoint breakpoints[], uint32_t count);
void GetBreakpoints(Breakpoint* breakpoints, int& execs, int& reads, int& writes);
__forceinline int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address);
__forceinline int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address);
};
__forceinline int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address)
__forceinline int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address)
{
if (!_hasBreakpoint)
{
if(!_hasBreakpoint) {
return -1;
}
return InternalCheckBreakpoint(operationInfo, address);

View file

@ -28,10 +28,8 @@ BsxCart::BsxCart(Console* console, BsxMemoryPack* memPack) : BaseCoprocessor(Sne
_psRam = new uint8_t[_psRamSize];
console->GetSettings()->InitializeRam(_psRam, _psRamSize);
for (uint32_t i = 0; i < _psRamSize / 0x1000; i++)
{
_psRamHandlers.push_back(
unique_ptr<IMemoryHandler>(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam)));
for(uint32_t i = 0; i < _psRamSize / 0x1000; i++) {
_psRamHandlers.push_back(unique_ptr<IMemoryHandler>(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam)));
}
Reset();
@ -45,20 +43,14 @@ BsxCart::~BsxCart()
uint8_t BsxCart::Read(uint32_t addr)
{
uint8_t openBus = _memoryManager->GetOpenBus();
if ((addr & 0xFFFF) != 0x5000)
{
if((addr & 0xFFFF) != 0x5000) {
return openBus;
}
else
{
} else {
uint8_t reg = (addr >> 16) & 0x0F;
if (reg <= 0x0D)
{
if(reg <= 0x0D) {
return (_regs[reg] << 7) | (openBus & 0x7F);
}
else
{
} else {
//E & F are write-only
return openBus & 0x7F;
}
@ -67,26 +59,20 @@ uint8_t BsxCart::Read(uint32_t addr)
void BsxCart::Write(uint32_t addr, uint8_t value)
{
if ((addr & 0xFFFF) != 0x5000)
{
if((addr & 0xFFFF) != 0x5000) {
return;
}
uint8_t reg = (addr >> 16) & 0x0F;
if (reg == 0x0E)
{
if (_dirty)
{
if(reg == 0x0E) {
if(_dirty) {
memcpy(_regs, _dirtyRegs, sizeof(_regs));
UpdateMemoryMappings();
_dirty = false;
}
}
else
{
} else {
uint8_t regValue = (value >> 7);
if (_regs[reg] != regValue)
{
if(_regs[reg] != regValue) {
_dirtyRegs[reg] = regValue;
_dirty = true;
}
@ -102,8 +88,7 @@ void BsxCart::UpdateMemoryMappings()
uint8_t unmappedBank = (_regs[0x0B] << 5);
uint8_t psRamBank = (_regs[0x05] << 4) | (_regs[0x06] << 5);
if (!_regs[0x02])
{
if(!_regs[0x02]) {
//LoROM
//Memory pack mapping
@ -114,32 +99,26 @@ void BsxCart::UpdateMemoryMappings()
//Memory hole mapping
uint16_t unmappedAddr = _regs[0x0B] ? 0x0000 : 0x8000;
if (_regs[0x09])
{
if(_regs[0x09]) {
mm->RegisterHandler(0x00 | (unmappedBank << 1), 0x1F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr);
}
if (_regs[0x0A])
{
if(_regs[0x0A]) {
mm->RegisterHandler(0x80 | (unmappedBank << 1), 0x9F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr);
}
//PSRAM mapping
uint16_t psRamAddr = (psRamBank & 0x20) ? 0x0000 : 0x8000;
if (_regs[0x03])
{
if(_regs[0x03]) {
mm->RegisterHandler(0x00 | (psRamBank << 1), 0x0F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _psRamHandlers);
}
if (_regs[0x04])
{
if(_regs[0x04]) {
mm->RegisterHandler(0x80 | (psRamBank << 1), 0x8F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _psRamHandlers);
}
}
else
{
} else {
//HiROM
//Memory pack mapping
@ -149,29 +128,25 @@ void BsxCart::UpdateMemoryMappings()
mm->RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, memPackHandlers, 0);
//Memory hole mapping
if (_regs[0x09])
{
if(_regs[0x09]) {
mm->RegisterHandler(0x00 | unmappedBank, 0x0F | unmappedBank, 0x8000, 0xFFFF, nullptr);
mm->RegisterHandler(0x40 | unmappedBank, 0x4F | unmappedBank, 0x0000, 0xFFFF, nullptr);
}
if (_regs[0x0A])
{
if(_regs[0x0A]) {
mm->RegisterHandler(0x80 | unmappedBank, 0x8F | unmappedBank, 0x8000, 0xFFFF, nullptr);
mm->RegisterHandler(0xC0 | unmappedBank, 0xCF | unmappedBank, 0x0000, 0xFFFF, nullptr);
}
//PSRAM mapping
if (_regs[0x03])
{
if(_regs[0x03]) {
//Lower Banks (0x00-0x7D)
mm->RegisterHandler(0x00 | psRamBank, 0x07 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8);
mm->RegisterHandler(0x40 | psRamBank, 0x47 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0x20, 0x3F, 0x6000, 0x7FFF, _psRamHandlers, 6);
}
if (_regs[0x04])
{
if(_regs[0x04]) {
//Higher Banks (0x80-0xFF)
mm->RegisterHandler(0x80 | psRamBank, 0x87 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8);
mm->RegisterHandler(0xC0 | psRamBank, 0xC7 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers);
@ -180,20 +155,17 @@ void BsxCart::UpdateMemoryMappings()
}
//BS-X BIOS mapping (can override other mappings above)
if (_regs[0x07])
{
if(_regs[0x07]) {
mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgHandlers);
}
if (_regs[0x08])
{
if(_regs[0x08]) {
mm->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, prgHandlers);
}
}
void BsxCart::Reset()
{
for (int i = 0; i < 0x10; i++)
{
for(int i = 0; i < 0x10; i++) {
_regs[i] = true;
}
@ -212,14 +184,13 @@ void BsxCart::Reset()
void BsxCart::Serialize(Serializer& s)
{
ArrayInfo<uint8_t> psRam = {_psRam, _psRamSize};
ArrayInfo<uint8_t> regs = {_regs, 0x10};
ArrayInfo<uint8_t> dirtyRegs = {_dirtyRegs, 0x10};
ArrayInfo<uint8_t> psRam = { _psRam, _psRamSize };
ArrayInfo<uint8_t> regs = { _regs, 0x10 };
ArrayInfo<uint8_t> dirtyRegs = { _dirtyRegs, 0x10 };
s.Stream(psRam, regs, dirtyRegs, _dirty);
s.Stream(_satellaview.get());
if (!s.IsSaving())
{
if(!s.IsSaving()) {
UpdateMemoryMappings();
}
}
@ -236,7 +207,7 @@ void BsxCart::PeekBlock(uint32_t addr, uint8_t* output)
AddressInfo BsxCart::GetAbsoluteAddress(uint32_t address)
{
return {-1, SnesMemoryType::Register};
return { -1, SnesMemoryType::Register };
}
uint8_t* BsxCart::DebugGetPsRam()

View file

@ -15,8 +15,7 @@ BsxMemoryPack::BsxMemoryPack(Console* console, vector<uint8_t>& data, bool persi
_calculatedSize = std::min<uint8_t>(0x0C, (uint8_t)log2(_dataSize >> 10));
for (uint32_t i = 0; i < _dataSize / 0x1000; i++)
{
for(uint32_t i = 0; i < _dataSize / 0x1000; i++) {
_handlers.push_back(unique_ptr<BsxMemoryPackHandler>(new BsxMemoryPackHandler(this, i * 0x1000)));
}
}
@ -28,8 +27,7 @@ BsxMemoryPack::~BsxMemoryPack()
void BsxMemoryPack::SaveBattery()
{
if (_persistFlash)
{
if(_persistFlash) {
_console->GetBatteryManager()->SaveBattery(".bs", _data, _dataSize);
}
}
@ -38,23 +36,19 @@ void BsxMemoryPack::Serialize(Serializer& s)
{
s.Stream(_enableCsr, _enableEsr, _enableVendorInfo, _writeByte, _command);
if (s.IsSaving())
{
if(s.IsSaving()) {
//Save content of memory pack as an IPS patch
vector<uint8_t> newData(_data, _data + _dataSize);
vector<uint8_t> ipsData = IpsPatcher::CreatePatch(_orgData, newData);
VectorInfo<uint8_t> data{&ipsData};
VectorInfo<uint8_t> data { &ipsData };
s.Stream(data);
}
else
{
} else {
//Apply IPS patch to original data and overwrite the current data
vector<uint8_t> ipsData;
VectorInfo<uint8_t> data{&ipsData};
VectorInfo<uint8_t> data { &ipsData };
s.Stream(data);
if (ipsData.size() > 8)
{
if(ipsData.size() > 8) {
vector<uint8_t> output;
IpsPatcher::PatchBuffer(ipsData, _orgData, output);
memcpy(_data, output.data(), _dataSize);
@ -66,8 +60,7 @@ void BsxMemoryPack::ProcessCommand(uint8_t value, uint32_t page)
{
_command = (_command << 8) | value;
switch (value)
{
switch(value) {
case 0x00:
case 0xFF:
_enableCsr = false;
@ -80,20 +73,14 @@ void BsxMemoryPack::ProcessCommand(uint8_t value, uint32_t page)
_writeByte = true;
break;
case 0x70: _enableCsr = true;
break;
case 0x71: _enableEsr = true;
break;
case 0x75: _enableVendorInfo = true;
break;
case 0x70: _enableCsr = true; break;
case 0x71: _enableEsr = true; break;
case 0x75: _enableVendorInfo = true; break;
}
switch (_command)
{
case 0x20D0: memset(_data + page * 0x10000, 0xFF, 0x10000);
break; //Page erase
case 0xA7D0: memset(_data, 0xFF, _dataSize);
break; //Chip erase
switch(_command) {
case 0x20D0: memset(_data + page * 0x10000, 0xFF, 0x10000); break; //Page erase
case 0xA7D0: memset(_data, 0xFF, _dataSize); break; //Chip erase
}
}
@ -121,8 +108,7 @@ uint32_t BsxMemoryPack::DebugGetMemoryPackSize()
return _dataSize;
}
BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset) : RamHandler(
memPack->_data, offset, memPack->_dataSize, SnesMemoryType::BsxMemoryPack)
BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset) : RamHandler(memPack->_data, offset, memPack->_dataSize, SnesMemoryType::BsxMemoryPack)
{
_memPack = memPack;
_page = offset / 0x10000;
@ -130,26 +116,21 @@ BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack
uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr)
{
if (_offset == 0 && _memPack->_enableEsr)
{
switch (addr & 0xFFF)
{
if(_offset == 0 && _memPack->_enableEsr) {
switch(addr & 0xFFF) {
case 0x0002: return 0xC0;
case 0x0004: return 0x82;
}
}
if (_memPack->_enableCsr)
{
if(_memPack->_enableCsr) {
_memPack->_enableCsr = false;
return 0x80;
}
if (_memPack->_enableVendorInfo && ((addr & 0x7FFF) >= 0x7F00) && ((addr & 0x7FFF) <= 0x7F13))
{
if(_memPack->_enableVendorInfo && ((addr & 0x7FFF) >= 0x7F00) && ((addr & 0x7FFF) <= 0x7F13)) {
//Flash cartridge vendor information
switch (addr & 0xFF)
{
switch(addr & 0xFF) {
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
@ -167,14 +148,11 @@ uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr)
void BsxMemoryPack::BsxMemoryPackHandler::Write(uint32_t addr, uint8_t value)
{
if (_memPack->_writeByte)
{
if(_memPack->_writeByte) {
uint8_t currentByte = RamHandler::Read(addr);
RamHandler::Write(addr, value & currentByte);
_memPack->_writeByte = false;
}
else if (_offset == 0 && (addr & 0xFFF) == 0)
{
} else if(_offset == 0 && (addr & 0xFFF) == 0) {
_memPack->ProcessCommand(value, _page);
}
}

View file

@ -21,12 +21,9 @@ void BsxSatellaview::Reset()
_extOutput = 0xFF;
time_t resetDate;
if (_customDate >= 0)
{
if(_customDate >= 0) {
resetDate = (time_t)_customDate;
}
else
{
} else {
//Use the current date/time as the BS-X date/time
time(&resetDate);
}
@ -38,13 +35,11 @@ void BsxSatellaview::Reset()
uint8_t BsxSatellaview::Read(uint32_t addr)
{
addr &= 0xFFFF;
if (addr >= 0x2188 && addr <= 0x219F)
{
if(addr >= 0x2188 && addr <= 0x219F) {
//Handle BS-X $2188-219F registers
ProcessClocks();
switch (addr)
{
switch(addr) {
case 0x2188: return _stream[0].GetChannel() & 0xFF;
case 0x2189: return (_stream[0].GetChannel()) >> 8;
case 0x218A: return _stream[0].GetPrefixCount();
@ -76,39 +71,25 @@ uint8_t BsxSatellaview::Read(uint32_t addr)
void BsxSatellaview::Write(uint32_t addr, uint8_t value)
{
addr &= 0xFFFF;
if (addr >= 0x2188 && addr <= 0x219F)
{
if(addr >= 0x2188 && addr <= 0x219F) {
//Handle BS-X register writes
ProcessClocks();
switch (addr)
{
case 0x2188: _stream[0].SetChannelLow(value);
break;
case 0x2189: _stream[0].SetChannelHigh(value);
break;
case 0x218B: _stream[0].SetPrefixLatch(value);
break;
case 0x218C: _stream[0].SetDataLatch(value);
break;
switch(addr) {
case 0x2188: _stream[0].SetChannelLow(value); break;
case 0x2189: _stream[0].SetChannelHigh(value); break;
case 0x218B: _stream[0].SetPrefixLatch(value); break;
case 0x218C: _stream[0].SetDataLatch(value); break;
case 0x218E: _stream[1].SetChannelLow(value);
break;
case 0x218F: _stream[1].SetChannelHigh(value);
break;
case 0x2191: _stream[1].SetPrefixLatch(value);
break;
case 0x2192: _stream[1].SetDataLatch(value);
break;
case 0x218E: _stream[1].SetChannelLow(value); break;
case 0x218F: _stream[1].SetChannelHigh(value); break;
case 0x2191: _stream[1].SetPrefixLatch(value); break;
case 0x2192: _stream[1].SetDataLatch(value); break;
case 0x2194: _streamReg = value;
break;
case 0x2197: _extOutput = value;
break;
case 0x2194: _streamReg = value; break;
case 0x2197: _extOutput = value; break;
}
}
else
{
} else {
//Regular B-bus handler
_bBusHandler->Write(addr, value);
}
@ -116,16 +97,13 @@ void BsxSatellaview::Write(uint32_t addr, uint8_t value)
void BsxSatellaview::ProcessClocks()
{
if (_stream[0].NeedUpdate() || _stream[1].NeedUpdate())
{
if(_stream[0].NeedUpdate() || _stream[1].NeedUpdate()) {
uint64_t gap = _memoryManager->GetMasterClock() - _prevMasterClock;
uint64_t clocksPerFrame = _console->GetMasterClockRate() / 1000; //1000 frames/sec (224kbits/sec)
while (gap >= clocksPerFrame)
{
while(gap >= clocksPerFrame) {
bool needUpdate = _stream[0].FillQueues() || _stream[1].FillQueues();
if (!needUpdate)
{
if(!needUpdate) {
gap = 0;
break;
}
@ -133,9 +111,7 @@ void BsxSatellaview::ProcessClocks()
}
_prevMasterClock = _memoryManager->GetMasterClock() - gap;
}
else
{
} else {
_prevMasterClock = _memoryManager->GetMasterClock();
}
}
@ -152,7 +128,7 @@ void BsxSatellaview::PeekBlock(uint32_t addr, uint8_t* output)
AddressInfo BsxSatellaview::GetAbsoluteAddress(uint32_t address)
{
return {-1, SnesMemoryType::Register};
return { -1, SnesMemoryType::Register };
}
void BsxSatellaview::Serialize(Serializer& s)

View file

@ -24,7 +24,7 @@ private:
void ProcessClocks();
public:
BsxSatellaview(Console* console, IMemoryHandler* bBusHandler);
BsxSatellaview(Console* console, IMemoryHandler *bBusHandler);
void Reset();

View file

@ -53,15 +53,12 @@ bool BsxStream::NeedUpdate()
bool BsxStream::FillQueues()
{
if (_queueLength > 0)
{
if(_queueLength > 0) {
_queueLength--;
if (_prefixLatch && _prefixQueueLength < 0x80)
{
if(_prefixLatch && _prefixQueueLength < 0x80) {
_prefixQueueLength++;
}
if (_dataLatch && _dataQueueLength < 0x80)
{
if(_dataLatch && _dataQueueLength < 0x80) {
_dataQueueLength++;
}
}
@ -83,23 +80,18 @@ bool BsxStream::LoadStreamFile()
OpenStreamFile();
if (_file)
{
if(_file) {
_firstPacket = true;
_file.seekg(0, ios::end);
_queueLength = (uint16_t)std::ceil(_file.tellg() / 22.0);
_file.seekg(0, ios::beg);
_fileIndex++;
return true;
}
else
{
if (_fileIndex > 0)
{
} else {
if(_fileIndex > 0) {
//Go back to file #0 and try again
_fileIndex = 0;
if (LoadStreamFile())
{
if(LoadStreamFile()) {
return true;
}
}
@ -112,24 +104,19 @@ bool BsxStream::LoadStreamFile()
uint8_t BsxStream::GetPrefixCount()
{
if (!_prefixLatch || !_dataLatch)
{
if(!_prefixLatch || !_dataLatch) {
//Stream is disabled
return 0;
}
if (_prefixQueueLength == 0 && _dataQueueLength == 0)
{
if(_prefixQueueLength == 0 && _dataQueueLength == 0) {
//Queue is empty, try to load in new data
_fileOffset = 0;
if (_channel == 0)
{
if(_channel == 0) {
//Time channel
_queueLength = 1;
_firstPacket = true;
}
else
{
} else {
LoadStreamFile();
}
}
@ -139,23 +126,19 @@ uint8_t BsxStream::GetPrefixCount()
uint8_t BsxStream::GetPrefix()
{
if (!_prefixLatch)
{
if(!_prefixLatch) {
return 0;
}
if (_prefixQueueLength > 0)
{
if(_prefixQueueLength > 0) {
_prefix = 0;
if (_firstPacket)
{
if(_firstPacket) {
_prefix |= 0x10;
_firstPacket = false;
}
_prefixQueueLength--;
if (_queueLength == 0 && _prefixQueueLength == 0)
{
if(_queueLength == 0 && _prefixQueueLength == 0) {
//Last packet
_prefix |= 0x80;
}
@ -168,20 +151,15 @@ uint8_t BsxStream::GetPrefix()
uint8_t BsxStream::GetData()
{
if (!_dataLatch)
{
if(!_dataLatch) {
return 0;
}
if (_dataQueueLength > 0)
{
if (_channel == 0)
{
if(_dataQueueLength > 0) {
if(_channel == 0) {
//Return Time
_data = GetTime();
}
else if (_file)
{
} else if(_file) {
//Read byte from stream file
char byte;
_file.get(byte);
@ -189,8 +167,7 @@ uint8_t BsxStream::GetData()
}
_fileOffset++;
if (_fileOffset % 22 == 0)
{
if(_fileOffset % 22 == 0) {
//Finished reading current packet
_dataQueueLength--;
}
@ -202,8 +179,7 @@ uint8_t BsxStream::GetData()
uint8_t BsxStream::GetStatus(bool reset)
{
uint8_t status = _status;
if (reset)
{
if(reset) {
_status = 0;
}
return status;
@ -211,8 +187,7 @@ uint8_t BsxStream::GetStatus(bool reset)
void BsxStream::SetChannelLow(uint8_t value)
{
if ((_channel & 0xFF) != 0xFF)
{
if((_channel & 0xFF) != 0xFF) {
_fileIndex = 0;
}
_channel = (_channel & 0xFF00) | value;
@ -220,8 +195,7 @@ void BsxStream::SetChannelLow(uint8_t value)
void BsxStream::SetChannelHigh(uint8_t value)
{
if ((_channel >> 8) != (value & 0x3F))
{
if((_channel >> 8) != (value & 0x3F)) {
_fileIndex = 0;
}
_channel = (_channel & 0xFF) | ((value & 0x3F) << 8);
@ -241,8 +215,7 @@ void BsxStream::SetDataLatch(uint8_t value)
void BsxStream::InitTimeStruct()
{
time_t dateTime = _resetDate + ((_memoryManager->GetMasterClock() - _resetMasterClock) / _console->
GetMasterClockRate());
time_t dateTime = _resetDate + ((_memoryManager->GetMasterClock() - _resetMasterClock) / _console->GetMasterClockRate());
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_s(&_tm, &dateTime);
@ -257,13 +230,11 @@ void BsxStream::InitTimeStruct()
uint8_t BsxStream::GetTime()
{
if (_fileOffset == 0)
{
if(_fileOffset == 0) {
InitTimeStruct();
}
switch (_fileOffset)
{
switch(_fileOffset) {
case 0: return 0x00; //Data Group ID / Repetition
case 1: return 0x00; //Data Group Link / Continuity
case 2: return 0x00; //Data Group Size (24-bit)
@ -290,17 +261,14 @@ void BsxStream::Serialize(Serializer& s)
{
s.Stream(
_channel, _prefix, _data, _status, _prefixLatch, _dataLatch, _firstPacket, _fileOffset, _fileIndex,
_queueLength, _prefixQueueLength, _dataQueueLength, _resetDate, _resetMasterClock, _activeChannel,
_activeFileIndex
_queueLength, _prefixQueueLength, _dataQueueLength, _resetDate, _resetMasterClock, _activeChannel, _activeFileIndex
);
if (!s.IsSaving())
{
if(!s.IsSaving()) {
InitTimeStruct();
OpenStreamFile();
if (_file)
{
if(_file) {
//Seek back to the previous location
_file.seekg(_fileOffset, ios::beg);
}

View file

@ -14,11 +14,9 @@ CallstackManager::~CallstackManager()
{
}
void CallstackManager::Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret,
uint32_t returnAddress, StackFrameFlags flags)
void CallstackManager::Push(AddressInfo &src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags)
{
if (_callstack.size() >= 511)
{
if(_callstack.size() >= 511) {
//Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
_callstack.pop_front();
}
@ -38,8 +36,7 @@ void CallstackManager::Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& des
void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
{
if (_callstack.empty())
{
if(_callstack.empty()) {
return;
}
@ -49,18 +46,14 @@ void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
uint32_t returnAddr = prevFrame.Return;
if (!_callstack.empty() && destAddress != returnAddr)
{
if(!_callstack.empty() && destAddress != returnAddr) {
//Mismatch, pop that stack frame and add the new one
bool foundMatch = false;
for (int i = (int)_callstack.size() - 1; i >= 0; i--)
{
if (destAddress == _callstack[i].Return)
{
for(int i = (int)_callstack.size() - 1; i >= 0; i--) {
if(destAddress == _callstack[i].Return) {
//Found a matching stack frame, unstack until that point
foundMatch = true;
for (int j = (int)_callstack.size() - i - 1; j >= 0; j--)
{
for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) {
_callstack.pop_back();
_profiler->UnstackFunction();
}
@ -68,21 +61,18 @@ void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
}
}
if (!foundMatch)
{
if(!foundMatch) {
//Couldn't find a matching frame, replace the current one
Push(prevFrame.AbsReturn, returnAddr, dest, destAddress, prevFrame.AbsReturn, returnAddr,
StackFrameFlags::None);
Push(prevFrame.AbsReturn, returnAddr, dest, destAddress, prevFrame.AbsReturn, returnAddr, StackFrameFlags::None);
}
}
}
void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t& callstackSize)
void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize)
{
DebugBreakHelper helper(_debugger);
int i = 0;
for (StackFrameInfo& info : _callstack)
{
for(StackFrameInfo &info : _callstack) {
callstackArray[i] = info;
i++;
}
@ -92,8 +82,7 @@ void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t& ca
int32_t CallstackManager::GetReturnAddress()
{
DebugBreakHelper helper(_debugger);
if (_callstack.empty())
{
if(_callstack.empty()) {
return -1;
}
return _callstack.back().Return;

View file

@ -16,11 +16,10 @@ public:
CallstackManager(Debugger* debugger);
~CallstackManager();
void Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret,
uint32_t returnAddress, StackFrameFlags flags);
void Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags);
void Pop(AddressInfo& dest, uint32_t destAddr);
void GetCallstack(StackFrameInfo* callstackArray, uint32_t& callstackSize);
void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize);
int32_t GetReturnAddress();
Profiler* GetProfiler();
};

View file

@ -17,13 +17,11 @@ void CheatManager::AddCheat(CheatCode code)
_hasCheats = true;
_bankHasCheats[code.Address >> 16] = true;
if (code.Address >= 0x7E0000 && code.Address < 0x7E2000)
{
if(code.Address >= 0x7E0000 && code.Address < 0x7E2000) {
//Mirror codes for the first 2kb of workram across all workram mirrors
CheatCode mirror;
mirror.Value = code.Value;
for (int i = 0; i < 0x3F; i++)
{
for(int i = 0; i < 0x3F; i++) {
mirror.Address = (i << 16) | (code.Address & 0xFFFF);
AddCheat(mirror);
mirror.Address |= 0x800000;
@ -38,21 +36,15 @@ void CheatManager::SetCheats(vector<CheatCode> codes)
bool hasCheats = !_cheats.empty();
ClearCheats(false);
for (CheatCode& code : codes)
{
for(CheatCode &code : codes) {
AddCheat(code);
}
if (codes.size() > 1)
{
if(codes.size() > 1) {
MessageManager::DisplayMessage("Cheats", "CheatsApplied", std::to_string(codes.size()));
}
else if (codes.size() == 1)
{
} else if(codes.size() == 1) {
MessageManager::DisplayMessage("Cheats", "CheatApplied");
}
else if (hasCheats)
{
} else if(hasCheats) {
MessageManager::DisplayMessage("Cheats", "CheatsDisabled");
}
@ -63,8 +55,7 @@ void CheatManager::SetCheats(uint32_t codes[], uint32_t length)
{
vector<CheatCode> cheats;
cheats.reserve(length);
for (uint32_t i = 0; i < length; i++)
{
for(uint32_t i = 0; i < length; i++) {
CheatCode code;
code.Address = codes[i] >> 8;
code.Value = codes[i] & 0xFF;
@ -84,8 +75,7 @@ void CheatManager::ClearCheats(bool showMessage)
_hasCheats = false;
memset(_bankHasCheats, 0, sizeof(_bankHasCheats));
if (showMessage && hadCheats)
{
if(showMessage && hadCheats) {
MessageManager::DisplayMessage("Cheats", "CheatsDisabled");
//Used by net play
@ -101,17 +91,13 @@ void CheatManager::AddStringCheat(string code)
std::transform(code.begin(), code.end(), code.begin(), ::toupper);
if (code.size() == 9 && code[4] == '-')
{
if(code.size() == 9 && code[4] == '-') {
uint32_t rawValue = 0;
for (int i = 0; i < (int)code.size(); i++)
{
if (code[i] != '-')
{
for(int i = 0; i < (int)code.size(); i++) {
if(code[i] != '-') {
rawValue <<= 4;
size_t pos = _convertTable.find_first_of(code[i]);
if (pos == string::npos)
{
if(pos == string::npos) {
//Invalid code
return;
}
@ -133,13 +119,9 @@ void CheatManager::AddStringCheat(string code)
cheat.Value = rawValue >> 24;
AddCheat(cheat);
}
else if (code.size() == 8)
{
for (int i = 0; i < (int)code.size(); i++)
{
if ((code[i] < 'A' || code[i] > 'F') && (code[i] < '0' || code[i] > '9'))
{
} else if(code.size() == 8) {
for(int i = 0; i < (int)code.size(); i++) {
if((code[i] < 'A' || code[i] > 'F') && (code[i] < '0' || code[i] > '9')) {
//Invalid code
return;
}

View file

@ -31,16 +31,14 @@ public:
vector<CheatCode> GetCheats();
__forceinline void ApplyCheat(uint32_t addr, uint8_t& value);
__forceinline void ApplyCheat(uint32_t addr, uint8_t &value);
};
__forceinline void CheatManager::ApplyCheat(uint32_t addr, uint8_t& value)
__forceinline void CheatManager::ApplyCheat(uint32_t addr, uint8_t &value)
{
if (_hasCheats && _bankHasCheats[addr >> 16])
{
if(_hasCheats && _bankHasCheats[addr >> 16]) {
auto result = _cheatsByAddress.find(addr);
if (result != _cheatsByAddress.end())
{
if(result != _cheatsByAddress.end()) {
value = result->second.Value;
}
}

View file

@ -11,9 +11,7 @@ public:
string PlayerName;
bool Spectator;
ClientConnectionData()
{
}
ClientConnectionData() {}
ClientConnectionData(string host, uint16_t port, string password, string playerName, bool spectator) :
Host(host), Port(port), Password(password), PlayerName(playerName), Spectator(spectator)

View file

@ -30,31 +30,23 @@ uint32_t CodeDataLogger::GetPrgSize()
bool CodeDataLogger::LoadCdlFile(string cdlFilepath, bool autoResetCdl, uint32_t romCrc)
{
VirtualFile cdlFile = cdlFilepath;
if (cdlFile.IsValid())
{
if(cdlFile.IsValid()) {
uint32_t fileSize = (uint32_t)cdlFile.GetSize();
vector<uint8_t> cdlData;
cdlFile.ReadFile(cdlData);
if (fileSize >= _prgSize)
{
if(fileSize >= _prgSize) {
Reset();
constexpr int headerSize = 9; //"CDLv2" + 4-byte CRC32 value
if (memcmp(cdlData.data(), "CDLv2", 5) == 0)
{
if(memcmp(cdlData.data(), "CDLv2", 5) == 0) {
uint32_t savedCrc = cdlData[5] | (cdlData[6] << 8) | (cdlData[7] << 16) | (cdlData[8] << 24);
if ((autoResetCdl && savedCrc != romCrc) || fileSize < _prgSize + headerSize)
{
if((autoResetCdl && savedCrc != romCrc) || fileSize < _prgSize + headerSize) {
memset(_cdlData, 0, _prgSize);
}
else
{
} else {
memcpy(_cdlData, cdlData.data() + headerSize, _prgSize);
}
}
else
{
} else {
//Older CRC-less CDL file, use as-is without checking CRC to avoid data loss
memcpy(_cdlData, cdlData.data(), _prgSize);
}
@ -70,8 +62,7 @@ bool CodeDataLogger::LoadCdlFile(string cdlFilepath, bool autoResetCdl, uint32_t
bool CodeDataLogger::SaveCdlFile(string cdlFilepath, uint32_t romCrc)
{
ofstream cdlFile(cdlFilepath, ios::out | ios::binary);
if (cdlFile)
{
if(cdlFile) {
cdlFile.write("CDLv2", 5);
cdlFile.put(romCrc & 0xFF);
cdlFile.put((romCrc >> 8) & 0xFF);
@ -89,14 +80,10 @@ void CodeDataLogger::CalculateStats()
uint32_t codeSize = 0;
uint32_t dataSize = 0;
for (int i = 0, len = _prgSize; i < len; i++)
{
if (IsCode(i))
{
for(int i = 0, len = _prgSize; i < len; i++) {
if(IsCode(i)) {
codeSize++;
}
else if (IsData(i))
{
} else if(IsData(i)) {
dataSize++;
}
}
@ -107,24 +94,15 @@ void CodeDataLogger::CalculateStats()
void CodeDataLogger::SetFlags(int32_t absoluteAddr, uint8_t flags)
{
if (absoluteAddr >= 0 && absoluteAddr < (int32_t)_prgSize)
{
if ((_cdlData[absoluteAddr] & flags) != flags)
{
if (flags & CdlFlags::Code)
{
_cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 |
CdlFlags::MemoryMode8));
}
else if (flags & CdlFlags::Data)
{
if (!IsCode(absoluteAddr))
{
if(absoluteAddr >= 0 && absoluteAddr < (int32_t)_prgSize) {
if((_cdlData[absoluteAddr] & flags) != flags) {
if(flags & CdlFlags::Code) {
_cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
} else if(flags & CdlFlags::Data) {
if(!IsCode(absoluteAddr)) {
_cdlData[absoluteAddr] |= flags;
}
}
else
{
} else {
_cdlData[absoluteAddr] |= flags;
}
}
@ -169,31 +147,25 @@ uint8_t CodeDataLogger::GetCpuFlags(uint32_t absoluteAddr)
CpuType CodeDataLogger::GetCpuType(uint32_t absoluteAddr)
{
if (_cpuType == CpuType::Gameboy)
{
if(_cpuType == CpuType::Gameboy) {
return _cpuType;
}
else if (_cdlData[absoluteAddr] & CdlFlags::Gsu)
{
} else if(_cdlData[absoluteAddr] & CdlFlags::Gsu) {
return CpuType::Gsu;
}
else if (_cdlData[absoluteAddr] & CdlFlags::Cx4)
{
} else if(_cdlData[absoluteAddr] & CdlFlags::Cx4) {
return CpuType::Cx4;
}
return CpuType::Cpu;
}
void CodeDataLogger::SetCdlData(uint8_t* cdlData, uint32_t length)
void CodeDataLogger::SetCdlData(uint8_t *cdlData, uint32_t length)
{
if (length <= _prgSize)
{
if(length <= _prgSize) {
memcpy(_cdlData, cdlData, length);
}
}
void CodeDataLogger::GetCdlData(uint32_t offset, uint32_t length, uint8_t* cdlData)
void CodeDataLogger::GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData)
{
memcpy(cdlData, _cdlData + offset, length);
}
@ -205,30 +177,22 @@ uint8_t CodeDataLogger::GetFlags(uint32_t addr)
void CodeDataLogger::MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags)
{
for (uint32_t i = start; i <= end; i++)
{
for(uint32_t i = start; i <= end; i++) {
_cdlData[i] = (_cdlData[i] & 0xFC) | (int)flags;
}
}
void CodeDataLogger::StripData(uint8_t* romBuffer, CdlStripOption flag)
{
if (flag == CdlStripOption::StripUnused)
{
for (uint32_t i = 0; i < _prgSize; i++)
{
if (_cdlData[i] == 0)
{
if(flag == CdlStripOption::StripUnused) {
for(uint32_t i = 0; i < _prgSize; i++) {
if(_cdlData[i] == 0) {
romBuffer[i] = 0;
}
}
}
else if (flag == CdlStripOption::StripUsed)
{
for (uint32_t i = 0; i < _prgSize; i++)
{
if (_cdlData[i] != 0)
{
} else if(flag == CdlStripOption::StripUsed) {
for(uint32_t i = 0; i < _prgSize; i++) {
if(_cdlData[i] != 0) {
romBuffer[i] = 0;
}
}

View file

@ -34,8 +34,8 @@ public:
uint8_t GetCpuFlags(uint32_t absoluteAddr);
CpuType GetCpuType(uint32_t absoluteAddr);
void SetCdlData(uint8_t* cdlData, uint32_t length);
void GetCdlData(uint32_t offset, uint32_t length, uint8_t* cdlData);
void SetCdlData(uint8_t *cdlData, uint32_t length);
void GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData);
uint8_t GetFlags(uint32_t addr);
void MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags);

View file

@ -97,18 +97,13 @@ void Console::Release()
void Console::RunFrame()
{
_frameRunning = true;
if (_settings->CheckFlag(EmulationFlags::GameboyMode))
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
Gameboy* gameboy = _cart->GetGameboy();
while (_frameRunning)
{
while(_frameRunning) {
gameboy->Exec();
}
}
else
{
while (_frameRunning)
{
} else {
while(_frameRunning) {
_cpu->Exec();
}
}
@ -116,8 +111,7 @@ void Console::RunFrame()
void Console::Run()
{
if (!_cpu)
{
if(!_cpu) {
return;
}
@ -140,20 +134,14 @@ void Console::Run()
_frameLimiter.reset(new FrameLimiter(_frameDelay));
_lastFrameTimer.Reset();
while (!_stopFlag)
{
bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager->
IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100;
if (useRunAhead)
{
while(!_stopFlag) {
bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager->IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100;
if(useRunAhead) {
RunFrameWithRunAhead();
}
else
{
} else {
RunFrame();
if (_historyViewer)
{
if (_historyViewer) {
_historyViewer->ProcessEndOfFrame();
}
_rewindManager->ProcessEndOfFrame();
@ -162,19 +150,16 @@ void Console::Run()
WaitForLock();
if (_pauseOnNextFrame)
{
if(_pauseOnNextFrame) {
_pauseOnNextFrame = false;
_paused = true;
}
if (_paused && !_stopFlag && !_debugger)
{
if(_paused && !_stopFlag && !_debugger) {
WaitForPauseEnd();
}
if (_memoryManager->GetMasterClock() == 0)
{
if(_memoryManager->GetMasterClock() == 0) {
//After a reset or power cycle, run the PPU/etc ahead of the CPU (simulates delay CPU takes to get out of reset)
_memoryManager->IncMasterClockStartup();
}
@ -189,13 +174,10 @@ void Console::Run()
bool Console::ProcessSystemActions()
{
if (_controlManager->GetSystemActionManager()->IsResetPressed())
{
if(_controlManager->GetSystemActionManager()->IsResetPressed()) {
Reset();
return true;
}
else if (_controlManager->GetSystemActionManager()->IsPowerCyclePressed())
{
} else if(_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) {
PowerCycle();
return true;
}
@ -212,8 +194,7 @@ void Console::RunFrameWithRunAhead()
RunFrame();
Serialize(runAheadState, 0);
while (frameCount > 1)
{
while(frameCount > 1) {
//Run extra frames if the requested run ahead frame count is higher than 1
frameCount--;
RunFrame();
@ -225,8 +206,7 @@ void Console::RunFrameWithRunAhead()
_rewindManager->ProcessEndOfFrame();
bool wasReset = ProcessSystemActions();
if (!wasReset)
{
if(!wasReset) {
//Load the state we saved earlier
_isRunAheadFrame = true;
Deserialize(runAheadState, SaveStateManager::FileFormatVersion, false);
@ -238,33 +218,27 @@ void Console::ProcessEndOfFrame()
{
#ifndef LIBRETRO
_cart->RunCoprocessors();
if (_cart->GetCoprocessor())
{
if(_cart->GetCoprocessor()) {
_cart->GetCoprocessor()->ProcessEndOfFrame();
}
if (!_isRunAheadFrame)
{
if(!_isRunAheadFrame) {
_frameLimiter->ProcessFrame();
while (_frameLimiter->WaitForNextFrame())
{
if (_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0)
{
while(_frameLimiter->WaitForNextFrame()) {
if(_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) {
//Need to process another event, stop sleeping
break;
}
}
double newFrameDelay = GetFrameDelay();
if (newFrameDelay != _frameDelay)
{
if(newFrameDelay != _frameDelay) {
_frameDelay = newFrameDelay;
_frameLimiter->SetDelay(_frameDelay);
}
PreferencesConfig cfg = _settings->GetPreferences();
if (cfg.ShowDebugInfo)
{
if(cfg.ShowDebugInfo) {
double lastFrameTime = _lastFrameTimer.GetElapsedMS();
_lastFrameTimer.Reset();
_stats->DisplayStats(this, lastFrameTime);
@ -290,8 +264,7 @@ void Console::RunSingleFrame()
RunFrame();
_cart->RunCoprocessors();
if (_cart->GetCoprocessor())
{
if(_cart->GetCoprocessor()) {
_cart->GetCoprocessor()->ProcessEndOfFrame();
}
@ -305,28 +278,24 @@ void Console::Stop(bool sendNotification)
_notificationManager->SendNotification(ConsoleNotificationType::BeforeGameUnload);
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
debugger->SuspendDebugger(false);
debugger->Run();
}
_emulationLock.WaitForRelease();
if (_emuThread)
{
if(_emuThread) {
_emuThread->join();
_emuThread.release();
}
if (_cart && !_settings->GetPreferences().DisableGameSelectionScreen)
{
if(_cart && !_settings->GetPreferences().DisableGameSelectionScreen) {
RomInfo romInfo = _cart->GetRomInfo();
_saveStateManager->SaveRecentGame(romInfo.RomFile.GetFileName(), romInfo.RomFile, romInfo.PatchFile);
}
if (sendNotification)
{
if(sendNotification) {
_notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop);
}
@ -352,8 +321,7 @@ void Console::Stop(bool sendNotification)
_soundMixer->StopAudio(true);
if (sendNotification)
{
if(sendNotification) {
_notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped);
}
}
@ -379,18 +347,14 @@ void Console::Reset()
_notificationManager->SendNotification(ConsoleNotificationType::GameReset);
ProcessEvent(EventType::Reset);
if (_cart->GetSpcData())
{
if(_cart->GetSpcData()) {
_spc->LoadSpcFile(_cart->GetSpcData());
_spcHud.reset(new SpcHud(this, _cart->GetSpcData()));
}
else
{
} else {
_spcHud.reset();
}
if (debugger)
{
if(debugger) {
//Debugger was suspended in SystemActionManager::Reset(), resume debugger here
debugger->SuspendDebugger(true);
}
@ -402,11 +366,9 @@ void Console::Reset()
void Console::ReloadRom(bool forPowerCycle)
{
shared_ptr<BaseCartridge> cart = _cart;
if (cart)
{
if(cart) {
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
debugger->Run();
}
@ -424,21 +386,17 @@ void Console::PowerCycle()
bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, bool forPowerCycle)
{
if (_cart)
{
if(_cart) {
//Make sure the battery is saved to disk before we load another game (or reload the same game)
_cart->SaveBattery();
}
bool result = false;
EmulationConfig orgConfig = _settings->GetEmulationConfig();
//backup emulation config (can be temporarily overriden to control the power on RAM state)
EmulationConfig orgConfig = _settings->GetEmulationConfig(); //backup emulation config (can be temporarily overriden to control the power on RAM state)
shared_ptr<BaseCartridge> cart = forPowerCycle ? _cart : BaseCartridge::CreateCartridge(this, romFile, patchFile);
if (cart)
{
if(cart) {
bool debuggerActive = _debugger != nullptr;
if (stopRom)
{
if(stopRom) {
KeyManager::UpdateDevices();
Stop(false);
}
@ -448,8 +406,7 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
_cart = cart;
auto lock = _debuggerLock.AcquireSafe();
if (_debugger)
{
if(_debugger) {
//Reset debugger if it was running before
_debugger->Release();
_debugger.reset();
@ -468,13 +425,10 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
_msu1.reset(Msu1::Init(romFile, _spc.get()));
if (_cart->GetSpcData())
{
if(_cart->GetSpcData()) {
_spc->LoadSpcFile(_cart->GetSpcData());
_spcHud.reset(new SpcHud(this, _cart->GetSpcData()));
}
else
{
} else {
_spcHud.reset();
}
@ -482,20 +436,16 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
_memoryManager->Initialize(this);
_internalRegisters->Initialize(this);
if (_cart->GetCoprocessor() == nullptr && _cart->GetGameboy())
{
if(_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) {
_cart->GetGameboy()->PowerOn();
_consoleType = _cart->GetGameboy()->IsCgb() ? ConsoleType::GameboyColor : ConsoleType::Gameboy;
_settings->SetFlag(EmulationFlags::GameboyMode);
}
else
{
} else {
_consoleType = ConsoleType::Snes;
_settings->ClearFlag(EmulationFlags::GameboyMode);
}
if (debuggerActive)
{
if(debuggerActive) {
GetDebugger();
}
@ -513,24 +463,19 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
_paused = false;
if (!forPowerCycle)
{
if(!forPowerCycle) {
string modelName = _region == ConsoleRegion::Pal ? "PAL" : "NTSC";
string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")";
MessageManager::DisplayMessage(messageTitle,
FolderUtilities::GetFilename(GetRomInfo().RomFile.GetFileName(), false));
MessageManager::DisplayMessage(messageTitle, FolderUtilities::GetFilename(GetRomInfo().RomFile.GetFileName(), false));
}
if (stopRom)
{
#ifndef LIBRETRO
if(stopRom) {
#ifndef LIBRETRO
_emuThread.reset(new thread(&Console::Run, this));
#endif
#endif
}
result = true;
}
else
{
} else {
MessageManager::DisplayMessage("Error", "CouldNotLoadFile", romFile.GetFileName());
}
@ -541,24 +486,18 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
RomInfo Console::GetRomInfo()
{
shared_ptr<BaseCartridge> cart = _cart;
if (cart)
{
if(cart) {
return cart->GetRomInfo();
}
else
{
} else {
return {};
}
}
uint64_t Console::GetMasterClock()
{
if (_settings->CheckFlag(EmulationFlags::GameboyMode) && _cart->GetGameboy())
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode) && _cart->GetGameboy()) {
return _cart->GetGameboy()->GetCycleCount();
}
else
{
} else {
return _memoryManager->GetMasterClock();
}
}
@ -580,16 +519,12 @@ ConsoleType Console::GetConsoleType()
void Console::UpdateRegion()
{
switch (_settings->GetEmulationConfig().Region)
{
case ConsoleRegion::Auto: _region = _cart->GetRegion();
break;
switch(_settings->GetEmulationConfig().Region) {
case ConsoleRegion::Auto: _region = _cart->GetRegion(); break;
default:
case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc;
break;
case ConsoleRegion::Pal: _region = ConsoleRegion::Pal;
break;
case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; break;
case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; break;
}
_masterClockRate = _region == ConsoleRegion::Pal ? 21281370 : 21477270;
@ -597,18 +532,12 @@ void Console::UpdateRegion()
double Console::GetFps()
{
if (_settings->CheckFlag(EmulationFlags::GameboyMode))
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
return 59.72750056960583;
}
else
{
if (_region == ConsoleRegion::Ntsc)
{
} else {
if(_region == ConsoleRegion::Ntsc) {
return _settings->GetVideoConfig().IntegerFpsMode ? 60.0 : 60.0988118623484;
}
else
{
} else {
return _settings->GetVideoConfig().IntegerFpsMode ? 50.0 : 50.00697796826829;
}
}
@ -618,28 +547,17 @@ double Console::GetFrameDelay()
{
uint32_t emulationSpeed = _settings->GetEmulationSpeed();
double frameDelay;
if (emulationSpeed == 0)
{
if(emulationSpeed == 0) {
frameDelay = 0;
}
else
{
} else {
UpdateRegion();
if (_settings->CheckFlag(EmulationFlags::GameboyMode))
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
frameDelay = 16.74270629882813;
}
else
{
switch (_region)
{
} else {
switch(_region) {
default:
case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode
? 16.6666666666666666667
: 16.63926405550947;
break;
case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146;
break;
case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 16.6666666666666666667 : 16.63926405550947; break;
case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; break;
}
}
frameDelay /= (emulationSpeed / 100.0);
@ -669,19 +587,13 @@ void Console::CopyRewindData(shared_ptr<Console> sourceConsole)
void Console::PauseOnNextFrame()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if (_settings->CheckFlag(EmulationFlags::GameboyMode))
{
if(debugger) {
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
debugger->Step(CpuType::Gameboy, 144, StepType::SpecificScanline);
}
else
{
} else {
debugger->Step(CpuType::Cpu, 240, StepType::SpecificScanline);
}
}
else
{
} else {
_pauseOnNextFrame = true;
_paused = false;
}
@ -690,19 +602,13 @@ void Console::PauseOnNextFrame()
void Console::Pause()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if (_settings->CheckFlag(EmulationFlags::GameboyMode))
{
if(debugger) {
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
debugger->Step(CpuType::Gameboy, 1, StepType::Step);
}
else
{
} else {
debugger->Step(CpuType::Cpu, 1, StepType::Step);
}
}
else
{
} else {
_paused = true;
}
}
@ -710,12 +616,9 @@ void Console::Pause()
void Console::Resume()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
debugger->Run();
}
else
{
} else {
_paused = false;
}
}
@ -723,12 +626,9 @@ void Console::Resume()
bool Console::IsPaused()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
return debugger->IsExecutionStopped();
}
else
{
} else {
return _paused;
}
}
@ -743,16 +643,14 @@ void Console::WaitForPauseEnd()
PlatformUtilities::EnableScreensaver();
PlatformUtilities::RestoreTimerResolution();
while (_paused && !_stopFlag && !_debugger)
{
while(_paused && !_stopFlag && !_debugger) {
//Sleep until emulation is resumed
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
}
PlatformUtilities::DisableScreensaver();
_runLock.Acquire();
if (!_stopFlag)
{
if(!_stopFlag) {
_notificationManager->SendNotification(ConsoleNotificationType::GameResumed);
}
}
@ -765,8 +663,7 @@ ConsoleLock Console::AcquireLock()
void Console::Lock()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
debugger->SuspendDebugger(false);
}
@ -777,8 +674,7 @@ void Console::Lock()
void Console::Unlock()
{
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
if(debugger) {
debugger->SuspendDebugger(true);
}
@ -793,24 +689,18 @@ bool Console::IsThreadPaused()
void Console::WaitForLock()
{
if (_lockCounter > 0)
{
if(_lockCounter > 0) {
//Need to temporarely pause the emu (to save/load a state, etc.)
_runLock.Release();
_threadPaused = true;
//Spin wait until we are allowed to start again
while (_lockCounter > 0)
{
}
while(_lockCounter > 0) {}
shared_ptr<Debugger> debugger = _debugger;
if (debugger)
{
while (debugger->HasBreakRequest())
{
}
if(debugger) {
while(debugger->HasBreakRequest()) {}
}
_threadPaused = false;
@ -819,13 +709,12 @@ void Console::WaitForLock()
}
}
void Console::Serialize(ostream& out, int compressionLevel)
void Console::Serialize(ostream &out, int compressionLevel)
{
Serializer serializer(SaveStateManager::FileFormatVersion);
bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode);
if (!isGameboyMode)
{
if(!isGameboyMode) {
serializer.Stream(_cpu.get());
serializer.Stream(_memoryManager.get());
serializer.Stream(_ppu.get());
@ -834,26 +723,22 @@ void Console::Serialize(ostream& out, int compressionLevel)
serializer.Stream(_cart.get());
serializer.Stream(_controlManager.get());
serializer.Stream(_spc.get());
if (_msu1)
{
if(_msu1) {
serializer.Stream(_msu1.get());
}
}
else
{
} else {
serializer.Stream(_cart.get());
serializer.Stream(_controlManager.get());
}
serializer.Save(out, compressionLevel);
}
void Console::Deserialize(istream& in, uint32_t fileFormatVersion, bool compressed)
void Console::Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed)
{
Serializer serializer(in, fileFormatVersion, compressed);
bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode);
if (!isGameboyMode)
{
if(!isGameboyMode) {
serializer.Stream(_cpu.get());
serializer.Stream(_memoryManager.get());
serializer.Stream(_ppu.get());
@ -862,13 +747,10 @@ void Console::Deserialize(istream& in, uint32_t fileFormatVersion, bool compress
serializer.Stream(_cart.get());
serializer.Stream(_controlManager.get());
serializer.Stream(_spc.get());
if (_msu1)
{
if(_msu1) {
serializer.Stream(_msu1.get());
}
}
else
{
} else {
serializer.Stream(_cart.get());
serializer.Stream(_controlManager.get());
}
@ -978,13 +860,11 @@ shared_ptr<Msu1> Console::GetMsu1()
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
{
shared_ptr<Debugger> debugger = _debugger;
if (!debugger && autoStart)
{
if(!debugger && autoStart) {
//Lock to make sure we don't try to start debuggers in 2 separate threads at once
auto lock = _debuggerLock.AcquireSafe();
debugger = _debugger;
if (!debugger)
{
if(!debugger) {
debugger.reset(new Debugger(shared_from_this()));
_debugger = debugger;
}
@ -1028,44 +908,37 @@ bool Console::IsRunAheadFrame()
uint32_t Console::GetFrameCount()
{
shared_ptr<BaseCartridge> cart = _cart;
if (_settings->CheckFlag(EmulationFlags::GameboyMode) && cart->GetGameboy())
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode) && cart->GetGameboy()) {
GbPpu* ppu = cart->GetGameboy()->GetPpu();
return ppu ? ppu->GetFrameCount() : 0;
}
else
{
} else {
shared_ptr<Ppu> ppu = _ppu;
return ppu ? ppu->GetFrameCount() : 0;
}
}
template <CpuType type>
template<CpuType type>
void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
{
if (_debugger)
{
if(_debugger) {
_debugger->ProcessInterrupt<type>(originalPc, currentPc, forNmi);
}
}
void Console::ProcessEvent(EventType type)
{
if (type == EventType::EndFrame && _spcHud)
{
if(type == EventType::EndFrame && _spcHud) {
_spcHud->Draw(GetFrameCount());
}
if (_debugger)
{
if(_debugger) {
_debugger->ProcessEvent(type);
}
}
void Console::BreakImmediately(BreakSource source)
{
if (_debugger)
{
if(_debugger) {
_debugger->BreakImmediately(source);
}
}

View file

@ -141,8 +141,8 @@ public:
void Unlock();
bool IsThreadPaused();
void Serialize(ostream& out, int compressionLevel = 1);
void Deserialize(istream& in, uint32_t fileFormatVersion, bool compressed = true);
void Serialize(ostream &out, int compressionLevel = 1);
void Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed = true);
shared_ptr<SoundMixer> GetSoundMixer();
shared_ptr<VideoRenderer> GetVideoRenderer();
@ -181,75 +181,63 @@ public:
void CopyRewindData(shared_ptr<Console> sourceConsole);
template <CpuType type>
__forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if (_debugger)
template<CpuType type> __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryRead<type>(addr, value, opType);
}
}
template <CpuType type>
__forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if (_debugger)
template<CpuType type> __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryWrite<type>(addr, value, opType);
}
}
__forceinline void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType)
{
if (_debugger)
{
if(_debugger) {
_debugger->ProcessPpuRead(addr, value, memoryType);
}
}
__forceinline void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType)
{
if (_debugger)
{
if(_debugger) {
_debugger->ProcessPpuWrite(addr, value, memoryType);
}
}
__forceinline void ProcessWorkRamRead(uint32_t addr, uint8_t value)
{
if (_debugger)
{
if(_debugger) {
_debugger->ProcessWorkRamRead(addr, value);
}
}
__forceinline void ProcessWorkRamWrite(uint32_t addr, uint8_t value)
{
if (_debugger)
{
if(_debugger) {
_debugger->ProcessWorkRamWrite(addr, value);
}
}
template <CpuType cpuType>
__forceinline void ProcessPpuCycle()
{
if (_debugger)
template<CpuType cpuType> __forceinline void ProcessPpuCycle()
{
if(_debugger) {
_debugger->ProcessPpuCycle<cpuType>();
}
}
__forceinline void DebugLog(string log)
{
if (_debugger)
{
if(_debugger) {
_debugger->Log(log);
}
}
template <CpuType type>
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template<CpuType type> void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);
void BreakImmediately(BreakSource source);
};

View file

@ -3,7 +3,7 @@
#include "Console.h"
#include "Debugger.h"
ConsoleLock::ConsoleLock(Console* console)
ConsoleLock::ConsoleLock(Console *console)
{
_console = console;
_console->Lock();

View file

@ -7,9 +7,9 @@ class Debugger;
class ConsoleLock
{
private:
Console* _console = nullptr;
Console *_console = nullptr;
public:
ConsoleLock(Console* console);
ConsoleLock(Console *console);
~ConsoleLock();
};

View file

@ -7,7 +7,7 @@ struct ControlDeviceState
{
vector<uint8_t> State;
bool operator!=(ControlDeviceState& other)
bool operator!=(ControlDeviceState &other)
{
return State.size() != other.State.size() || memcmp(State.data(), other.State.data(), State.size()) != 0;
}

View file

@ -37,7 +37,7 @@ void ControlManager::RegisterInputProvider(IInputProvider* provider)
void ControlManager::UnregisterInputProvider(IInputProvider* provider)
{
auto lock = _deviceLock.AcquireSafe();
vector<IInputProvider*>& vec = _inputProviders;
vector<IInputProvider*> &vec = _inputProviders;
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
}
@ -50,7 +50,7 @@ void ControlManager::RegisterInputRecorder(IInputRecorder* provider)
void ControlManager::UnregisterInputRecorder(IInputRecorder* provider)
{
auto lock = _deviceLock.AcquireSafe();
vector<IInputRecorder*>& vec = _inputRecorders;
vector<IInputRecorder*> &vec = _inputRecorders;
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
}
@ -59,16 +59,12 @@ vector<ControllerData> ControlManager::GetPortStates()
auto lock = _deviceLock.AcquireSafe();
vector<ControllerData> states;
for (int i = 0; i < 2; i++)
{
for(int i = 0; i < 2; i++) {
shared_ptr<BaseControlDevice> device = GetControlDevice(i);
if (device)
{
states.push_back({device->GetControllerType(), device->GetRawState()});
}
else
{
states.push_back({ControllerType::None, ControlDeviceState()});
if(device) {
states.push_back({ device->GetControllerType(), device->GetRawState() });
} else {
states.push_back({ ControllerType::None, ControlDeviceState()});
}
}
return states;
@ -83,13 +79,8 @@ shared_ptr<BaseControlDevice> ControlManager::GetControlDevice(uint8_t port)
{
auto lock = _deviceLock.AcquireSafe();
auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(),
[port](const shared_ptr<BaseControlDevice> control)
{
return control->GetPort() == port;
});
if (result != _controlDevices.end())
{
auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), [port](const shared_ptr<BaseControlDevice> control) { return control->GetPort() == port; });
if(result != _controlDevices.end()) {
return *result;
}
return nullptr;
@ -110,26 +101,18 @@ ControllerType ControlManager::GetControllerType(uint8_t port)
return _console->GetSettings()->GetInputConfig().Controllers[port].Type;
}
shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerType type, uint8_t port,
Console* console)
shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, Console* console)
{
shared_ptr<BaseControlDevice> device;
InputConfig cfg = console->GetSettings()->GetInputConfig();
switch (type)
{
switch(type) {
case ControllerType::None: break;
case ControllerType::SnesController: device.reset(new SnesController(console, port, cfg.Controllers[port].Keys));
break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port));
break;
case ControllerType::SuperScope: device.reset(new SuperScope(console, port, cfg.Controllers[port].Keys));
break;
case ControllerType::Multitap: device.reset(new Multitap(console, port, cfg.Controllers[port].Keys,
cfg.Controllers[2].Keys, cfg.Controllers[3].Keys,
cfg.Controllers[4].Keys));
break;
case ControllerType::SnesController: device.reset(new SnesController(console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); break;
case ControllerType::SuperScope: device.reset(new SuperScope(console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::Multitap: device.reset(new Multitap(console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break;
}
return device;
@ -138,18 +121,15 @@ shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerT
void ControlManager::UpdateControlDevices()
{
uint32_t version = _console->GetSettings()->GetInputConfigVersion();
if (_inputConfigVersion != version)
{
if(_inputConfigVersion != version) {
_inputConfigVersion = version;
auto lock = _deviceLock.AcquireSafe();
_controlDevices.clear();
RegisterControlDevice(_systemActionManager);
for (int i = 0; i < 2; i++)
{
for(int i = 0; i < 2; i++) {
shared_ptr<BaseControlDevice> device = CreateControllerDevice(GetControllerType(i), i, _console);
if (device)
{
if(device) {
RegisterControlDevice(device);
}
}
@ -163,16 +143,13 @@ void ControlManager::UpdateInputState()
auto lock = _deviceLock.AcquireSafe();
//string log = "F: " + std::to_string(_console->GetPpu()->GetFrameCount()) + " C:" + std::to_string(_pollCounter) + " ";
for (shared_ptr<BaseControlDevice>& device : _controlDevices)
{
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
device->ClearState();
device->SetStateFromInput();
for (size_t i = 0; i < _inputProviders.size(); i++)
{
for(size_t i = 0; i < _inputProviders.size(); i++) {
IInputProvider* provider = _inputProviders[i];
if (provider->SetInput(device.get()))
{
if(provider->SetInput(device.get())) {
break;
}
}
@ -182,15 +159,12 @@ void ControlManager::UpdateInputState()
}
shared_ptr<Debugger> debugger = _console->GetDebugger(false);
if (debugger)
{
if(debugger) {
debugger->ProcessEvent(EventType::InputPolled);
}
if (!_console->IsRunAheadFrame())
{
for (IInputRecorder* recorder : _inputRecorders)
{
if(!_console->IsRunAheadFrame()) {
for(IInputRecorder* recorder : _inputRecorders) {
recorder->RecordInput(_controlDevices);
}
}
@ -213,8 +187,7 @@ void ControlManager::SetPollCounter(uint32_t value)
uint8_t ControlManager::Read(uint16_t addr)
{
uint8_t value = _console->GetMemoryManager()->GetOpenBus() & (addr == 0x4016 ? 0xFC : 0xE0);
for (shared_ptr<BaseControlDevice>& device : _controlDevices)
{
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
value |= device->ReadRam(addr);
}
@ -223,25 +196,21 @@ uint8_t ControlManager::Read(uint16_t addr)
void ControlManager::Write(uint16_t addr, uint8_t value)
{
for (shared_ptr<BaseControlDevice>& device : _controlDevices)
{
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
device->WriteRam(addr, value);
}
}
void ControlManager::Serialize(Serializer& s)
void ControlManager::Serialize(Serializer &s)
{
InputConfig cfg = _console->GetSettings()->GetInputConfig();
s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type,
cfg.Controllers[4].Type);
if (!s.IsSaving())
{
s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type, cfg.Controllers[4].Type);
if(!s.IsSaving()) {
_console->GetSettings()->SetInputConfig(cfg);
UpdateControlDevices();
}
for (shared_ptr<BaseControlDevice>& device : _controlDevices)
{
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
s.Stream(device.get());
}
}

View file

@ -60,5 +60,5 @@ public:
uint8_t Read(uint16_t addr);
void Write(uint16_t addr, uint8_t value);
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

@ -4,36 +4,28 @@ Add/substract operations
void Cpu::Add8(uint8_t value)
{
uint32_t result;
if (CheckFlag(ProcFlags::Decimal))
{
if(CheckFlag(ProcFlags::Decimal)) {
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
if (result > 0x09) result += 0x06;
if(result > 0x09) result += 0x06;
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
}
else
{
} else {
result = (_state.A & 0xFF) + value + (_state.PS & ProcFlags::Carry);
}
if (~(_state.A ^ value) & (_state.A ^ result) & 0x80)
{
if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) {
SetFlags(ProcFlags::Overflow);
}
else
{
} else {
ClearFlags(ProcFlags::Overflow);
}
if (CheckFlag(ProcFlags::Decimal) && result > 0x9F)
{
if(CheckFlag(ProcFlags::Decimal) && result > 0x9F) {
result += 0x60;
}
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
SetZeroNegativeFlags((uint8_t)result);
if (result > 0xFF)
{
if(result > 0xFF) {
SetFlags(ProcFlags::Carry);
}
@ -43,43 +35,35 @@ void Cpu::Add8(uint8_t value)
void Cpu::Add16(uint16_t value)
{
uint32_t result;
if (CheckFlag(ProcFlags::Decimal))
{
if(CheckFlag(ProcFlags::Decimal)) {
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
if (result > 0x09) result += 0x06;
if(result > 0x09) result += 0x06;
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
if (result > 0x9F) result += 0x60;
if(result > 0x9F) result += 0x60;
result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF);
if (result > 0x9FF) result += 0x600;
if(result > 0x9FF) result += 0x600;
result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF);
}
else
{
} else {
result = _state.A + value + (_state.PS & ProcFlags::Carry);
}
if (~(_state.A ^ value) & (_state.A ^ result) & 0x8000)
{
if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) {
SetFlags(ProcFlags::Overflow);
}
else
{
} else {
ClearFlags(ProcFlags::Overflow);
}
if (CheckFlag(ProcFlags::Decimal) && result > 0x9FFF)
{
if(CheckFlag(ProcFlags::Decimal) && result > 0x9FFF) {
result += 0x6000;
}
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
SetZeroNegativeFlags((uint16_t)result);
if (result > 0xFFFF)
{
if(result > 0xFFFF) {
SetFlags(ProcFlags::Carry);
}
@ -88,12 +72,9 @@ void Cpu::Add16(uint16_t value)
void Cpu::ADC()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
Add8(GetByteValue());
}
else
{
} else {
Add16(GetWordValue());
}
}
@ -101,36 +82,28 @@ void Cpu::ADC()
void Cpu::Sub8(uint8_t value)
{
int32_t result;
if (CheckFlag(ProcFlags::Decimal))
{
if(CheckFlag(ProcFlags::Decimal)) {
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
if (result <= 0x0F) result -= 0x06;
if(result <= 0x0F) result -= 0x06;
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
}
else
{
} else {
result = (_state.A & 0xFF) + value + (_state.PS & ProcFlags::Carry);
}
if (~(_state.A ^ value) & (_state.A ^ result) & 0x80)
{
if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) {
SetFlags(ProcFlags::Overflow);
}
else
{
} else {
ClearFlags(ProcFlags::Overflow);
}
if (CheckFlag(ProcFlags::Decimal) && result <= 0xFF)
{
if(CheckFlag(ProcFlags::Decimal) && result <= 0xFF) {
result -= 0x60;
}
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
SetZeroNegativeFlags((uint8_t)result);
if (result > 0xFF)
{
if(result > 0xFF) {
SetFlags(ProcFlags::Carry);
}
@ -140,43 +113,35 @@ void Cpu::Sub8(uint8_t value)
void Cpu::Sub16(uint16_t value)
{
int32_t result;
if (CheckFlag(ProcFlags::Decimal))
{
if(CheckFlag(ProcFlags::Decimal)) {
result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry);
if (result <= 0x0F) result -= 0x06;
if(result <= 0x0F) result -= 0x06;
result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
if (result <= 0xFF) result -= 0x60;
if(result <= 0xFF) result -= 0x60;
result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF);
if (result <= 0xFFF) result -= 0x600;
if(result <= 0xFFF) result -= 0x600;
result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF);
}
else
{
} else {
result = _state.A + value + (_state.PS & ProcFlags::Carry);
}
if (~(_state.A ^ value) & (_state.A ^ result) & 0x8000)
{
if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) {
SetFlags(ProcFlags::Overflow);
}
else
{
} else {
ClearFlags(ProcFlags::Overflow);
}
if (CheckFlag(ProcFlags::Decimal) && result <= 0xFFFF)
{
if(CheckFlag(ProcFlags::Decimal) && result <= 0xFFFF) {
result -= 0x6000;
}
ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero);
SetZeroNegativeFlags((uint16_t)result);
if (result > 0xFFFF)
{
if(result > 0xFFFF) {
SetFlags(ProcFlags::Carry);
}
@ -185,12 +150,9 @@ void Cpu::Sub16(uint16_t value)
void Cpu::SBC()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
Sub8(~GetByteValue());
}
else
{
} else {
Sub16(~GetWordValue());
}
}
@ -251,12 +213,10 @@ void Cpu::BVS()
void Cpu::BranchRelative(bool branch)
{
if (branch)
{
if(branch) {
int8_t offset = _operand;
Idle();
if (_state.EmulationMode && ((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00))
{
if(_state.EmulationMode && ((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) {
//Extra cycle in emulation mode if crossing a page
Idle();
}
@ -313,8 +273,7 @@ void Cpu::SEP()
{
Idle();
SetFlags((uint8_t)_operand);
if (CheckFlag(ProcFlags::IndexMode8))
{
if(CheckFlag(ProcFlags::IndexMode8)) {
//Truncate X/Y when 8-bit indexes are enabled
_state.Y &= 0xFF;
_state.X &= 0xFF;
@ -364,22 +323,19 @@ void Cpu::INC_Acc()
SetRegister(_state.A, _state.A + 1, CheckFlag(ProcFlags::MemoryMode8));
}
void Cpu::IncDecReg(uint16_t& reg, int8_t offset)
void Cpu::IncDecReg(uint16_t &reg, int8_t offset)
{
SetRegister(reg, reg + offset, CheckFlag(ProcFlags::IndexMode8));
}
void Cpu::IncDec(int8_t offset)
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue() + offset;
SetZeroNegativeFlags(value);
Idle();
Write(_operand, value);
}
else
{
} else {
uint16_t value = GetWordValue() + offset;
SetZeroNegativeFlags(value);
Idle();
@ -392,29 +348,20 @@ Compare instructions
*********************/
void Cpu::Compare(uint16_t reg, bool eightBitMode)
{
if (eightBitMode)
{
if(eightBitMode) {
uint8_t value = GetByteValue();
if ((uint8_t)reg >= value)
{
if((uint8_t)reg >= value) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
uint8_t result = (uint8_t)reg - value;
SetZeroNegativeFlags(result);
}
else
{
} else {
uint16_t value = GetWordValue();
if (reg >= value)
{
if(reg >= value) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
@ -476,13 +423,10 @@ void Cpu::RTI()
Idle();
Idle();
if (_state.EmulationMode)
{
if(_state.EmulationMode) {
SetPS(PopByte());
_state.PC = PopWord();
}
else
{
} else {
SetPS(PopByte());
_state.PC = PopWord();
_state.K = PopByte();
@ -517,15 +461,13 @@ Interrupts
***********/
void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt)
{
if (forHardwareInterrupt)
{
if(forHardwareInterrupt) {
//IRQ/NMI waste 2 cycles here. BRK/COP do not (because they do those 2 cycles while loading the OP code + signature byte)
ReadCode(_state.PC);
Idle();
}
if (_state.EmulationMode)
{
if(_state.EmulationMode) {
PushWord(_state.PC);
PushByte(_state.PS | 0x20);
@ -534,9 +476,7 @@ void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt)
_state.K = 0;
_state.PC = ReadVector(vector);
}
else
{
} else {
PushByte(_state.K);
PushWord(_state.PC);
PushByte(_state.PS);
@ -564,36 +504,27 @@ Bitwise operations
*******************/
void Cpu::AND()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
SetRegister(_state.A, _state.A & GetByteValue(), true);
}
else
{
} else {
SetRegister(_state.A, _state.A & GetWordValue(), false);
}
}
void Cpu::EOR()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
SetRegister(_state.A, _state.A ^ GetByteValue(), true);
}
else
{
} else {
SetRegister(_state.A, _state.A ^ GetWordValue(), false);
}
}
void Cpu::ORA()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
SetRegister(_state.A, _state.A | GetByteValue(), true);
}
else
{
} else {
SetRegister(_state.A, _state.A | GetWordValue(), false);
}
}
@ -601,64 +532,48 @@ void Cpu::ORA()
/****************
Shift operations
*****************/
template <typename T>
T Cpu::ShiftLeft(T value)
template<typename T> T Cpu::ShiftLeft(T value)
{
T result = value << 1;
if (value & (1 << (sizeof(T) * 8 - 1)))
{
if(value & (1 << (sizeof(T) * 8 - 1))) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
template <typename T>
T Cpu::RollLeft(T value)
template<typename T> T Cpu::RollLeft(T value)
{
T result = value << 1 | (_state.PS & ProcFlags::Carry);
if (value & (1 << (sizeof(T) * 8 - 1)))
{
if(value & (1 << (sizeof(T) * 8 - 1))) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
template <typename T>
T Cpu::ShiftRight(T value)
template<typename T> T Cpu::ShiftRight(T value)
{
T result = value >> 1;
if (value & 0x01)
{
if(value & 0x01) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
template <typename T>
T Cpu::RollRight(T value)
template<typename T> T Cpu::RollRight(T value)
{
T result = value >> 1 | ((_state.PS & 0x01) << (sizeof(T) * 8 - 1));
if (value & 0x01)
{
if(value & 0x01) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
SetZeroNegativeFlags(result);
@ -667,26 +582,20 @@ T Cpu::RollRight(T value)
void Cpu::ASL_Acc()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
_state.A = (_state.A & 0xFF00) | (ShiftLeft<uint8_t>((uint8_t)_state.A));
}
else
{
} else {
_state.A = ShiftLeft<uint16_t>(_state.A);
}
}
void Cpu::ASL()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, ShiftLeft<uint8_t>(value));
}
else
{
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, ShiftLeft<uint16_t>(value));
@ -695,26 +604,20 @@ void Cpu::ASL()
void Cpu::LSR_Acc()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
_state.A = (_state.A & 0xFF00) | ShiftRight<uint8_t>((uint8_t)_state.A);
}
else
{
} else {
_state.A = ShiftRight<uint16_t>(_state.A);
}
}
void Cpu::LSR()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, ShiftRight<uint8_t>(value));
}
else
{
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, ShiftRight<uint16_t>(value));
@ -723,26 +626,20 @@ void Cpu::LSR()
void Cpu::ROL_Acc()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
_state.A = (_state.A & 0xFF00) | RollLeft<uint8_t>((uint8_t)_state.A);
}
else
{
} else {
_state.A = RollLeft<uint16_t>(_state.A);
}
}
void Cpu::ROL()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, RollLeft<uint8_t>(value));
}
else
{
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, RollLeft<uint16_t>(value));
@ -751,26 +648,20 @@ void Cpu::ROL()
void Cpu::ROR_Acc()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
_state.A = (_state.A & 0xFF00) | RollRight<uint8_t>((uint8_t)_state.A);
}
else
{
} else {
_state.A = RollRight<uint16_t>(_state.A);
}
}
void Cpu::ROR()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, RollRight<uint8_t>(value));
}
else
{
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, RollRight<uint16_t>(value));
@ -794,16 +685,14 @@ void Cpu::MVN()
_state.X++;
_state.Y++;
if (CheckFlag(ProcFlags::IndexMode8))
{
if(CheckFlag(ProcFlags::IndexMode8)) {
_state.X &= 0xFF;
_state.Y &= 0xFF;
}
_state.A--;
if (_state.A != 0xFFFF)
{
if(_state.A != 0xFFFF) {
//Operation isn't done, set the PC back to the start of the instruction
_state.PC -= 3;
}
@ -823,16 +712,14 @@ void Cpu::MVP()
_state.X--;
_state.Y--;
if (CheckFlag(ProcFlags::IndexMode8))
{
if(CheckFlag(ProcFlags::IndexMode8)) {
_state.X &= 0xFF;
_state.Y &= 0xFF;
}
_state.A--;
if (_state.A != 0xFFFF)
{
if(_state.A != 0xFFFF) {
//Operation isn't done, set the PC back to the start of the instruction
_state.PC -= 3;
}
@ -906,12 +793,9 @@ void Cpu::PLP()
//"For PLP, (all of) the flags are pulled from the stack. Note that when the e flag is 1, the m and x flag are forced to 1, so after the PLP, both flags will still be 1 no matter what value is pulled from the stack."
Idle();
Idle();
if (_state.EmulationMode)
{
if(_state.EmulationMode) {
SetPS(PopByte() | ProcFlags::MemoryMode8 | ProcFlags::IndexMode8);
}
else
{
} else {
SetPS(PopByte());
}
}
@ -960,25 +844,19 @@ void Cpu::PLY()
void Cpu::PushRegister(uint16_t reg, bool eightBitMode)
{
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
if (eightBitMode)
{
if(eightBitMode) {
PushByte((uint8_t)reg);
}
else
{
} else {
PushWord(reg);
}
}
void Cpu::PullRegister(uint16_t& reg, bool eightBitMode)
void Cpu::PullRegister(uint16_t &reg, bool eightBitMode)
{
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
if (eightBitMode)
{
if(eightBitMode) {
SetRegister(reg, PopByte(), true);
}
else
{
} else {
SetRegister(reg, PopWord(), false);
}
}
@ -986,26 +864,20 @@ void Cpu::PullRegister(uint16_t& reg, bool eightBitMode)
/*********************
Store/load operations
**********************/
void Cpu::LoadRegister(uint16_t& reg, bool eightBitMode)
void Cpu::LoadRegister(uint16_t &reg, bool eightBitMode)
{
if (eightBitMode)
{
if(eightBitMode) {
SetRegister(reg, GetByteValue(), true);
}
else
{
} else {
SetRegister(reg, GetWordValue(), false);
}
}
void Cpu::StoreRegister(uint16_t val, bool eightBitMode)
{
if (eightBitMode)
{
if(eightBitMode) {
Write(_operand, (uint8_t)val);
}
else
{
} else {
WriteWord(_operand, val);
}
}
@ -1055,36 +927,26 @@ void Cpu::STZ()
/*******************
Bit test operations
********************/
template <typename T>
void Cpu::TestBits(T value, bool alterZeroFlagOnly)
template<typename T> void Cpu::TestBits(T value, bool alterZeroFlagOnly)
{
if (alterZeroFlagOnly)
{
if(alterZeroFlagOnly) {
//"Immediate addressing only affects the z flag (with the result of the bitwise And), but does not affect the n and v flags."
if (((T)_state.A & value) == 0)
{
if(((T)_state.A & value) == 0) {
SetFlags(ProcFlags::Zero);
}
else
{
} else {
ClearFlags(ProcFlags::Zero);
}
}
else
{
} else {
ClearFlags(ProcFlags::Zero | ProcFlags::Overflow | ProcFlags::Negative);
if (((T)_state.A & value) == 0)
{
if(((T)_state.A & value) == 0) {
SetFlags(ProcFlags::Zero);
}
if (value & (1 << (sizeof(T) * 8 - 2)))
{
if(value & (1 << (sizeof(T) * 8 - 2))) {
SetFlags(ProcFlags::Overflow);
}
if (value & (1 << (sizeof(T) * 8 - 1)))
{
if(value & (1 << (sizeof(T) * 8 - 1))) {
SetFlags(ProcFlags::Negative);
}
}
@ -1092,20 +954,16 @@ void Cpu::TestBits(T value, bool alterZeroFlagOnly)
void Cpu::BIT()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
TestBits<uint8_t>(GetByteValue(), _immediateMode);
}
else
{
} else {
TestBits<uint16_t>(GetWordValue(), _immediateMode);
}
}
void Cpu::TRB()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
TestBits<uint8_t>(value, true);
@ -1113,9 +971,7 @@ void Cpu::TRB()
Idle();
Write(_operand, value);
}
else
{
} else {
uint16_t value = GetWordValue();
TestBits<uint16_t>(value, true);
@ -1128,8 +984,7 @@ void Cpu::TRB()
void Cpu::TSB()
{
if (CheckFlag(ProcFlags::MemoryMode8))
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
TestBits<uint8_t>(value, true);
@ -1137,9 +992,7 @@ void Cpu::TSB()
Idle();
Write(_operand, value);
}
else
{
} else {
uint16_t value = GetWordValue();
TestBits<uint16_t>(value, true);
@ -1223,18 +1076,14 @@ void Cpu::XBA()
void Cpu::XCE()
{
bool carry = CheckFlag(ProcFlags::Carry);
if (_state.EmulationMode)
{
if(_state.EmulationMode) {
SetFlags(ProcFlags::Carry);
}
else
{
} else {
ClearFlags(ProcFlags::Carry);
}
_state.EmulationMode = carry;
if (_state.EmulationMode)
{
if(_state.EmulationMode) {
SetPS(_state.PS | ProcFlags::IndexMode8 | ProcFlags::MemoryMode8);
_state.SP = 0x100 | (_state.SP & 0xFF);
}
@ -1280,8 +1129,7 @@ void Cpu::AddrMode_AbsIdxX(bool isWrite)
{
uint32_t baseAddr = GetDataAddress(ReadOperandWord());
_operand = (baseAddr + _state.X) & 0xFFFFFF;
if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00))
{
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}
@ -1290,8 +1138,7 @@ void Cpu::AddrMode_AbsIdxY(bool isWrite)
{
uint32_t baseAddr = GetDataAddress(ReadOperandWord());
_operand = (baseAddr + _state.Y) & 0xFFFFFF;
if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00))
{
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}
@ -1345,8 +1192,7 @@ void Cpu::AddrMode_BlkMov()
uint8_t Cpu::ReadDirectOperandByte()
{
uint8_t value = ReadOperandByte();
if (_state.D & 0xFF)
{
if(_state.D & 0xFF) {
//Add 1 cycle for direct register low (DL) not equal 0
Idle();
}
@ -1387,8 +1233,7 @@ void Cpu::AddrMode_DirIndIdxY(bool isWrite)
uint32_t baseAddr = GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte()));
_operand = (baseAddr + _state.Y) & 0xFFFFFF;
if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00))
{
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}

File diff suppressed because it is too large Load diff

View file

@ -26,22 +26,19 @@ void Cpu::Exec()
{
_immediateMode = false;
switch (_state.StopState)
{
case CpuStopState::Running: RunOp();
break;
switch(_state.StopState) {
case CpuStopState::Running: RunOp(); break;
case CpuStopState::Stopped:
//STP was executed, CPU no longer executes any code
#ifndef DUMMYCPU
#ifndef DUMMYCPU
_memoryManager->IncMasterClock4();
#endif
#endif
return;
case CpuStopState::WaitingForIrq:
//WAI
Idle();
if (_state.IrqSource || _state.NeedNmi)
{
if(_state.IrqSource || _state.NeedNmi) {
Idle();
Idle();
_state.StopState = CpuStopState::Running;
@ -123,33 +120,21 @@ void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
void Cpu::SetReg(CpuRegister reg, uint16_t value)
{
switch (reg)
{
case CpuRegister::CpuRegA: { _state.A = value; }
break;
case CpuRegister::CpuRegX: { _state.X = value; }
break;
case CpuRegister::CpuRegY: { _state.Y = value; }
break;
case CpuRegister::CpuRegSP: { _state.SP = value; }
break;
case CpuRegister::CpuRegD: { _state.D = value; }
break;
case CpuRegister::CpuRegPC: { _state.PC = value; }
break;
case CpuRegister::CpuRegK: { _state.K = value & 0xFF; }
break;
case CpuRegister::CpuRegDBR: { _state.DBR = value & 0xFF; }
break;
case CpuRegister::CpuRegPS: { _state.PS = value & 0xFF; }
break;
case CpuRegister::CpuFlagNmi: { _state.NmiFlag = value != 0; }
break;
switch (reg) {
case CpuRegister::CpuRegA: { _state.A = value; } break;
case CpuRegister::CpuRegX: { _state.X = value; } break;
case CpuRegister::CpuRegY: { _state.Y = value; } break;
case CpuRegister::CpuRegSP: { _state.SP = value; } break;
case CpuRegister::CpuRegD: { _state.D = value; } break;
case CpuRegister::CpuRegPC: { _state.PC = value; } break;
case CpuRegister::CpuRegK: { _state.K = value & 0xFF; } break;
case CpuRegister::CpuRegDBR: { _state.DBR = value & 0xFF; } break;
case CpuRegister::CpuRegPS: { _state.PS = value & 0xFF; } break;
case CpuRegister::CpuFlagNmi: { _state.NmiFlag = value != 0; } break;
}
}
bool Cpu::GetCpuProcFlag(ProcFlags::ProcFlags flag)
{
bool Cpu::GetCpuProcFlag(ProcFlags::ProcFlags flag) {
return _state.PS & static_cast<uint8_t>(flag);
}

View file

@ -29,11 +29,11 @@ private:
static constexpr uint32_t LegacyIrqVector = 0xFFFE;
static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4;
typedef void (Cpu::*Func)();
typedef void(Cpu::*Func)();
MemoryManager* _memoryManager = nullptr;
DmaController* _dmaController = nullptr;
Console* _console = nullptr;
MemoryManager *_memoryManager = nullptr;
DmaController *_dmaController = nullptr;
Console *_console = nullptr;
bool _immediateMode = false;
@ -71,8 +71,8 @@ private:
void SetSP(uint16_t sp);
void SetPS(uint8_t ps);
void SetRegister(uint8_t& reg, uint8_t value);
void SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode);
void SetRegister(uint8_t &reg, uint8_t value);
void SetRegister(uint16_t &reg, uint16_t value, bool eightBitMode);
void SetZeroNegativeFlags(uint16_t value);
void SetZeroNegativeFlags(uint8_t value);
@ -146,7 +146,7 @@ private:
void DEC_Acc();
void INC_Acc();
void IncDecReg(uint16_t& reg, int8_t offset);
void IncDecReg(uint16_t & reg, int8_t offset);
void IncDec(int8_t offset);
//Compare instructions
@ -174,14 +174,10 @@ private:
void EOR();
void ORA();
template <typename T>
T ShiftLeft(T value);
template <typename T>
T RollLeft(T value);
template <typename T>
T ShiftRight(T value);
template <typename T>
T RollRight(T value);
template<typename T> T ShiftLeft(T value);
template<typename T> T RollLeft(T value);
template<typename T> T ShiftRight(T value);
template<typename T> T RollRight(T value);
//Shift operations
void ASL_Acc();
@ -217,10 +213,10 @@ private:
void PLY();
void PushRegister(uint16_t reg, bool eightBitMode);
void PullRegister(uint16_t& reg, bool eightBitMode);
void PullRegister(uint16_t &reg, bool eightBitMode);
//Store/load instructions
void LoadRegister(uint16_t& reg, bool eightBitMode);
void LoadRegister(uint16_t &reg, bool eightBitMode);
void StoreRegister(uint16_t val, bool eightBitMode);
void LDA();
@ -233,8 +229,7 @@ private:
void STZ();
//Test bits
template <typename T>
void TestBits(T value, bool alterZeroFlagOnly);
template<typename T> void TestBits(T value, bool alterZeroFlagOnly);
void BIT();
void TRB();
@ -323,7 +318,7 @@ private:
public:
#ifndef DUMMYCPU
Cpu(Console* console);
Cpu(Console *console);
#else
DummyCpu(Console* console, CpuType type);
#endif
@ -339,7 +334,7 @@ public:
bool GetCpuProcFlag(ProcFlags::ProcFlags flag);
uint64_t GetCycleCount();
template <uint64_t value>
template<uint64_t value>
void IncreaseCycleCount();
void SetNmiFlag(bool nmiFlag);
@ -350,7 +345,7 @@ public:
void ClearIrqSource(IrqSource source);
// Inherited via ISerializable
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
void SetReg(CpuRegister reg, uint16_t value);
void SetCpuProcFlag(ProcFlags::ProcFlags flag, bool set);
@ -382,7 +377,7 @@ public:
void SetReg(CpuRegister reg, uint16_t value);
template <uint64_t count>
template<uint64_t count>
void Cpu::IncreaseCycleCount()
{
_state.CycleCount += count;

View file

@ -10,7 +10,7 @@
class CpuBwRamHandler : public IMemoryHandler
{
private:
IMemoryHandler* _handler;
IMemoryHandler * _handler;
Sa1State* _state;
Sa1* _sa1;
@ -24,12 +24,9 @@ public:
uint8_t Read(uint32_t addr) override
{
if (_state->CharConvDmaActive)
{
if(_state->CharConvDmaActive) {
return _sa1->ReadCharConvertType1(addr);
}
else
{
} else {
return _handler->Read(addr);
}
}
@ -39,7 +36,7 @@ public:
return Read(addr);
}
void PeekBlock(uint32_t addr, uint8_t* output) override
void PeekBlock(uint32_t addr, uint8_t *output) override
{
_handler->PeekBlock(addr, output);
}

View file

@ -37,15 +37,13 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
_settings = debugger->GetConsole()->GetSettings().get();
_memoryManager = debugger->GetConsole()->GetMemoryManager().get();
_eventManager.reset(new EventManager(debugger, _cpu, _debugger->GetConsole()->GetPpu().get(), _memoryManager,
_debugger->GetConsole()->GetDmaController().get()));
_eventManager.reset(new EventManager(debugger, _cpu, _debugger->GetConsole()->GetPpu().get(), _memoryManager, _debugger->GetConsole()->GetDmaController().get()));
_callstackManager.reset(new CallstackManager(debugger));
_breakpointManager.reset(new BreakpointManager(debugger, cpuType, _eventManager.get()));
_step.reset(new StepRequest());
_assembler.reset(new Assembler(_debugger->GetLabelManager()));
if (GetState().PC == 0)
{
if(GetState().PC == 0) {
//Enable breaking on uninit reads when debugger is opened at power on
_enableBreakOnUninitRead = true;
}
@ -61,34 +59,26 @@ void CpuDebugger::Reset()
void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
MemoryOperationInfo operation = {addr, value, type};
MemoryOperationInfo operation = { addr, value, type };
CpuState state = GetState();
BreakSource breakSource = BreakSource::Unspecified;
if (type == MemoryOperationType::ExecOpCode)
{
bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(
_cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled);
if (addressInfo.Address >= 0)
{
if (addressInfo.Type == SnesMemoryType::PrgRom)
{
if(type == MemoryOperationType::ExecOpCode) {
bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(_cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled);
if(addressInfo.Address >= 0) {
if(addressInfo.Type == SnesMemoryType::PrgRom) {
uint8_t flags = CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC)
{
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
flags |= CdlFlags::SubEntryPoint;
}
_codeDataLogger->SetFlags(addressInfo.Address, flags);
}
if (needDisassemble)
{
_disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8),
_cpuType);
if(needDisassemble) {
_disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), _cpuType);
}
}
if (_traceLogger->IsCpuLogged(_cpuType))
{
if(_traceLogger->IsCpuLogged(_cpuType)) {
_debugger->GetState(_debugState, true);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType);
@ -96,25 +86,19 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
uint32_t pc = (state.K << 16) | state.PC;
if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC)
{
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
//JSR, JSL
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc);
_callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc,
StackFrameFlags::None);
}
else if (_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40)
{
_callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None);
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
//RTS, RTL, RTI
_callstackManager->Pop(addressInfo, pc);
}
if (_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B ||
_prevOpCode == 0x44 || _prevOpCode == 0x54))
{
if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || _prevOpCode == 0x44 || _prevOpCode == 0x54)) {
//RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_step->StepCount = 0;
}
@ -122,72 +106,47 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevOpCode = value;
_prevProgramCounter = pc;
if (_step->StepCount > 0)
{
if(_step->StepCount > 0) {
_step->StepCount--;
}
if (_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled))
{
if (value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB)
{
if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled)) {
if(value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) {
//Break on BRK/STP/WDM/COP
if (value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk))
{
if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) {
breakSource = BreakSource::BreakOnBrk;
_step->StepCount = 0;
}
else if (value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop))
{
} else if(value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) {
breakSource = BreakSource::BreakOnCop;
_step->StepCount = 0;
}
else if (value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm))
{
} else if(value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) {
breakSource = BreakSource::BreakOnWdm;
_step->StepCount = 0;
}
else if (value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp))
{
} else if(value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) {
breakSource = BreakSource::BreakOnStp;
_step->StepCount = 0;
}
}
}
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
}
else if (type == MemoryOperationType::ExecOperand)
{
if (addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0)
{
_codeDataLogger->SetFlags(addressInfo.Address,
CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
} else if(type == MemoryOperationType::ExecOperand) {
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
}
else
{
if (addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0)
{
_codeDataLogger->SetFlags(addressInfo.Address,
CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
} else {
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
if (_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()))
{
if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock())) {
//Memory access was a read on an uninitialized memory address
if (_enableBreakOnUninitRead)
{
if (_memoryAccessCounter->GetReadCount(addressInfo) == 1)
{
if(_enableBreakOnUninitRead) {
if(_memoryAccessCounter->GetReadCount(addressInfo) == 1) {
//Only warn the first time
_debugger->Log(
string(_cpuType == CpuType::Sa1 ? "[SA1]" : "[CPU]") + " Uninitialized memory read: $" +
HexUtilities::ToHex24(addr));
_debugger->Log(string(_cpuType == CpuType::Sa1 ? "[SA1]" : "[CPU]") + " Uninitialized memory read: $" + HexUtilities::ToHex24(addr));
}
if (_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled) && _settings->CheckDebuggerFlag(
DebuggerFlags::BreakOnUninitRead))
{
if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled) && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnUninitRead)) {
breakSource = BreakSource::BreakOnUninitMemoryRead;
_step->StepCount = 0;
}
@ -195,27 +154,22 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
}
if (IsRegister(addr))
{
if(IsRegister(addr)) {
_eventManager->AddEvent(DebugEventType::Register, operation);
}
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo,
breakSource);
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
}
void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
MemoryOperationInfo operation = {addr, value, type};
if (addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type ==
SnesMemoryType::SaveRam))
{
MemoryOperationInfo operation = { addr, value, type };
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
_disassembler->InvalidateCache(addressInfo, _cpuType);
}
if (IsRegister(addr))
{
if(IsRegister(addr)) {
_eventManager->AddEvent(DebugEventType::Register, operation);
}
@ -232,39 +186,25 @@ void CpuDebugger::Run()
void CpuDebugger::Step(int32_t stepCount, StepType type)
{
StepRequest step;
if ((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && GetState().StopState ==
CpuStopState::Stopped)
{
if((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && GetState().StopState == CpuStopState::Stopped) {
//If STP was called, the CPU isn't running anymore - use the PPU to break execution instead (useful for test roms that end with STP)
step.PpuStepCount = 1;
}
else
{
switch (type)
{
case StepType::Step: step.StepCount = stepCount;
break;
case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress();
break;
} else {
switch(type) {
case StepType::Step: step.StepCount = stepCount; break;
case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break;
case StepType::StepOver:
if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode ==
0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54)
{
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) {
//JSR, JSL, BRK, COP, MVP, MVN
step.BreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) +
DisassemblyInfo::GetOpSize(_prevOpCode, 0, _cpuType)) & 0xFFFF);
}
else
{
step.BreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, _cpuType)) & 0xFFFF);
} else {
//For any other instruction, step over is the same as step into
step.StepCount = 1;
}
break;
case StepType::PpuStep: step.PpuStepCount = stepCount;
break;
case StepType::SpecificScanline: step.BreakScanline = stepCount;
break;
case StepType::PpuStep: step.PpuStepCount = stepCount; break;
case StepType::SpecificScanline: step.BreakScanline = stepCount; break;
}
}
_step.reset(new StepRequest(step));
@ -275,24 +215,20 @@ void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
AddressInfo src = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc);
AddressInfo dest = GetMemoryMappings().GetAbsoluteAddress(currentPc);
_callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc,
forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
_callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
}
void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle)
{
if (_step->PpuStepCount > 0)
{
if(_step->PpuStepCount > 0) {
_step->PpuStepCount--;
if (_step->PpuStepCount == 0)
{
if(_step->PpuStepCount == 0) {
_debugger->SleepUntilResume(BreakSource::PpuStep);
}
}
if (cycle == 0 && scanline == _step->BreakScanline)
{
if(cycle == 0 && scanline == _step->BreakScanline) {
_step->BreakScanline = -1;
_debugger->SleepUntilResume(BreakSource::PpuStep);
}
@ -300,24 +236,18 @@ void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle)
MemoryMappings& CpuDebugger::GetMemoryMappings()
{
if (_cpuType == CpuType::Cpu)
{
if(_cpuType == CpuType::Cpu) {
return *_memoryManager->GetMemoryMappings();
}
else
{
} else {
return *_sa1->GetMemoryMappings();
}
}
CpuState CpuDebugger::GetState()
{
if (_cpuType == CpuType::Cpu)
{
if(_cpuType == CpuType::Cpu) {
return _cpu->GetState();
}
else
{
} else {
return _sa1->GetCpuState();
}
}

View file

@ -10,8 +10,7 @@
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.h"
void CpuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings)
void CpuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
{
FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
@ -24,93 +23,55 @@ void CpuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t me
uint32_t opSize = info.GetOpSize();
FastString operand(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
if (opSize > 1)
{
if (addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng || opSize == 4)
{
AddressInfo address{(int32_t)opAddr, SnesMemoryType::CpuMemory};
if(opSize > 1) {
if(addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng || opSize == 4) {
AddressInfo address { (int32_t)opAddr, SnesMemoryType::CpuMemory };
string label = labelManager ? labelManager->GetLabel(address) : "";
if (label.size())
{
if(label.size()) {
operand.Write(label, true);
}
else
{
} else {
operand.WriteAll('$', HexUtilities::ToHex24(opAddr));
}
}
else if (opSize == 2)
{
} else if(opSize == 2) {
operand.WriteAll('$', HexUtilities::ToHex((uint8_t)opAddr));
}
else if (opSize == 3)
{
} else if(opSize == 3) {
operand.WriteAll('$', HexUtilities::ToHex((uint16_t)opAddr));
}
}
switch (addrMode)
{
case AddrMode::Abs: str.Write(operand);
break;
case AddrMode::AbsJmp: str.Write(operand);
break;
case AddrMode::AbsIdxXInd: str.WriteAll('(', operand, ",X)");
break;
case AddrMode::AbsIdxX: str.WriteAll(operand, ",X");
break;
case AddrMode::AbsIdxY: str.WriteAll(operand, ",Y");
break;
case AddrMode::AbsInd: str.WriteAll('(', operand, ')');
break;
case AddrMode::AbsIndLng: str.WriteAll('[', operand, ']');
break;
case AddrMode::AbsLngIdxX: str.WriteAll(operand, ",X");
break;
case AddrMode::AbsLng: str.Write(operand);
break;
case AddrMode::AbsLngJmp: str.Write(operand);
break;
switch(addrMode) {
case AddrMode::Abs: str.Write(operand); break;
case AddrMode::AbsJmp: str.Write(operand); break;
case AddrMode::AbsIdxXInd: str.WriteAll('(', operand, ",X)"); break;
case AddrMode::AbsIdxX: str.WriteAll(operand, ",X"); break;
case AddrMode::AbsIdxY: str.WriteAll(operand, ",Y"); break;
case AddrMode::AbsInd: str.WriteAll('(', operand, ')'); break;
case AddrMode::AbsIndLng: str.WriteAll('[', operand, ']'); break;
case AddrMode::AbsLngIdxX: str.WriteAll(operand, ",X"); break;
case AddrMode::AbsLng: str.Write(operand); break;
case AddrMode::AbsLngJmp: str.Write(operand); break;
case AddrMode::Acc: break;
case AddrMode::BlkMov: str.WriteAll('$', operand[1], operand[2], ',');
str.WriteAll('$', operand[3], operand[4]);
break;
case AddrMode::DirIdxIndX: str.WriteAll('(', operand, ",X)");
break;
case AddrMode::DirIdxX: str.WriteAll(operand, ",X");
break;
case AddrMode::DirIdxY: str.WriteAll(operand, ",Y");
break;
case AddrMode::DirIndIdxY: str.WriteAll("(", operand, "),Y");
break;
case AddrMode::DirIndLngIdxY: str.WriteAll("[", operand, "],Y");
break;
case AddrMode::DirIndLng: str.WriteAll("[", operand, "]");
break;
case AddrMode::DirInd: str.WriteAll("(", operand, ")");
break;
case AddrMode::Dir: str.Write(operand);
break;
case AddrMode::BlkMov: str.WriteAll('$', operand[1], operand[2], ','); str.WriteAll('$', operand[3], operand[4]); break;
case AddrMode::DirIdxIndX: str.WriteAll('(', operand, ",X)"); break;
case AddrMode::DirIdxX: str.WriteAll(operand, ",X"); break;
case AddrMode::DirIdxY: str.WriteAll(operand, ",Y"); break;
case AddrMode::DirIndIdxY: str.WriteAll("(", operand, "),Y"); break;
case AddrMode::DirIndLngIdxY: str.WriteAll("[", operand, "],Y"); break;
case AddrMode::DirIndLng: str.WriteAll("[", operand, "]"); break;
case AddrMode::DirInd: str.WriteAll("(", operand, ")"); break;
case AddrMode::Dir: str.Write(operand); break;
case AddrMode::Imm8:
case AddrMode::Imm16:
case AddrMode::ImmX:
case AddrMode::ImmM:
case AddrMode::Imm8: case AddrMode::Imm16: case AddrMode::ImmX: case AddrMode::ImmM:
str.WriteAll('#', operand);
break;
case AddrMode::Sig8: str.WriteAll('#', operand);
break; //BRK/COP signature
case AddrMode::Sig8: str.WriteAll('#', operand); break; //BRK/COP signature
case AddrMode::Imp: break;
case AddrMode::RelLng: str.Write(operand);
break;
case AddrMode::Rel: str.Write(operand);
break;
case AddrMode::RelLng: str.Write(operand); break;
case AddrMode::Rel: str.Write(operand); break;
case AddrMode::Stk: break;
case AddrMode::StkRel: str.WriteAll(operand, ",S");
break;
case AddrMode::StkRelIndIdxY: str.WriteAll('(', operand, ",S),Y");
break;
case AddrMode::StkRel: str.WriteAll(operand, ",S"); break;
case AddrMode::StkRelIndIdxY: str.WriteAll('(', operand, ",S),Y"); break;
default: throw std::runtime_error("invalid address mode");
}
@ -118,33 +79,24 @@ void CpuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t me
out += str.ToString();
}
uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo& info, uint32_t memoryAddr)
uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo &info, uint32_t memoryAddr)
{
uint32_t opSize = info.GetOpSize();
uint32_t opAddr = 0;
uint8_t* byteCode = info.GetByteCode();
if (opSize == 2)
{
if(opSize == 2) {
opAddr = byteCode[1];
}
else if (opSize == 3)
{
} else if(opSize == 3) {
opAddr = byteCode[1] | (byteCode[2] << 8);
}
else if (opSize == 4)
{
} else if(opSize == 4) {
opAddr = byteCode[1] | (byteCode[2] << 8) | (byteCode[3] << 16);
}
AddrMode addrMode = CpuDisUtils::OpMode[byteCode[0]];
if (addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng)
{
if (opSize == 2)
{
if(addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng) {
if(opSize == 2) {
opAddr = (memoryAddr & 0xFF0000) | (((int8_t)opAddr + memoryAddr + 2) & 0xFFFF);
}
else
{
} else {
opAddr = (memoryAddr & 0xFF0000) | (((int16_t)opAddr + memoryAddr + 3) & 0xFFFF);
}
}
@ -152,10 +104,9 @@ uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo& info, uint32_t memoryAd
return opAddr;
}
int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, CpuState& state, CpuType type)
int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console, CpuState &state, CpuType type)
{
if (HasEffectiveAddress(CpuDisUtils::OpMode[info.GetOpCode()]))
{
if(HasEffectiveAddress(CpuDisUtils::OpMode[info.GetOpCode()])) {
DummyCpu cpu(console, type);
state.PS &= ~(ProcFlags::IndexMode8 | ProcFlags::MemoryMode8);
state.PS |= info.GetFlags();
@ -168,8 +119,7 @@ int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console
bool CpuDisUtils::HasEffectiveAddress(AddrMode addrMode)
{
switch (addrMode)
{
switch(addrMode) {
case AddrMode::Acc:
case AddrMode::Imp:
case AddrMode::Stk:
@ -211,12 +161,9 @@ bool CpuDisUtils::HasEffectiveAddress(AddrMode addrMode)
uint8_t CpuDisUtils::GetOpSize(AddrMode addrMode, uint8_t flags)
{
if (addrMode == AddrMode::ImmX)
{
if(addrMode == AddrMode::ImmX) {
return (flags & ProcFlags::IndexMode8) ? 2 : 3;
}
else if (addrMode == AddrMode::ImmM)
{
} else if(addrMode == AddrMode::ImmM) {
return (flags & ProcFlags::MemoryMode8) ? 2 : 3;
}
@ -258,36 +205,20 @@ string CpuDisUtils::OpName[256] = {
typedef AddrMode M;
AddrMode CpuDisUtils::OpMode[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
M::Sig8, M::DirIdxIndX, M::Sig8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk,
M::Abs, M::Abs, M::Abs, M::AbsLng, // 0
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1
M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk,
M::Abs, M::Abs, M::Abs, M::AbsLng, // 2
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3
M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk,
M::Abs, M::Abs, M::Abs, M::AbsLng, // 4
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5
M::Stk, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk,
M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7
M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk,
M::Abs, M::Abs, M::Abs, M::AbsLng, // 8
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9
M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk,
M::Abs, M::Abs, M::Abs, M::AbsLng, // A
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp,
M::Abs, M::Abs, M::Abs, M::AbsLng, // C
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp,
M::Abs, M::Abs, M::Abs, M::AbsLng, // E
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Imm16, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp,
M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F
M::Sig8, M::DirIdxIndX, M::Sig8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1
M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3
M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 4
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5
M::Stk, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7
M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9
M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Imm16, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F
};

View file

@ -13,7 +13,7 @@ class CpuDisUtils
{
private:
static uint8_t OpSize[0x1F];
static uint32_t GetOperandAddress(DisassemblyInfo& info, uint32_t memoryAddr);
static uint32_t GetOperandAddress(DisassemblyInfo &info, uint32_t memoryAddr);
static uint8_t GetOpSize(AddrMode addrMode, uint8_t flags);
static bool HasEffectiveAddress(AddrMode addrMode);
@ -22,10 +22,9 @@ public:
static string OpName[256];
static AddrMode OpMode[256];
static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings);
static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings);
static uint8_t GetOpSize(uint8_t opCode, uint8_t flags);
static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, CpuState& state, CpuType type);
static int32_t GetEffectiveAddress(DisassemblyInfo &info, Console* console, CpuState &state, CpuType type);
};
enum class AddrMode : uint8_t
@ -36,20 +35,15 @@ enum class AddrMode : uint8_t
ImmX,
ImmM,
Abs,
AbsIdxXInd,
//JMP/JSR only
AbsIdxXInd, //JMP/JSR only
AbsIdxX,
AbsIdxY,
AbsInd,
//JMP only
AbsIndLng,
//JML only
AbsInd, //JMP only
AbsIndLng, //JML only
AbsLngIdxX,
AbsLng,
AbsJmp,
//JSR/JMP only
AbsLngJmp,
//JSL/JMP only
AbsJmp, //JSR/JMP only
AbsLngJmp, //JSL/JMP only
Acc,
BlkMov,
DirIdxIndX,

View file

@ -88,3 +88,4 @@ enum class IrqSource
Ppu = 1,
Coprocessor = 2
};

View file

@ -4,7 +4,7 @@
#include "Cx4DisUtils.h"
#include "../Utilities/HexUtilities.h"
static constexpr int shiftLut[4] = {0, 1, 8, 16};
static constexpr int shiftLut[4] = { 0 , 1, 8, 16 };
extern const uint32_t _dataRom[1024];
@ -14,151 +14,86 @@ void Cx4::Exec(uint16_t opCode)
uint8_t param1 = (opCode >> 8) & 0x03;
uint8_t param2 = opCode & 0xFF;
switch (op)
{
case 0x00: NOP();
break;
case 0x04: NOP();
break; //???
case 0x08: Branch(true, param1, param2);
break;
case 0x0C: Branch(_state.Zero, param1, param2);
break;
switch(op) {
case 0x00: NOP(); break;
case 0x04: NOP(); break; //???
case 0x08: Branch(true, param1, param2); break;
case 0x0C: Branch(_state.Zero, param1, param2); break;
case 0x10: Branch(_state.Carry, param1, param2);
break;
case 0x14: Branch(_state.Negative, param1, param2);
break;
case 0x18: Branch(_state.Overflow, param1, param2);
break;
case 0x1C: WAIT();
break;
case 0x10: Branch(_state.Carry, param1, param2); break;
case 0x14: Branch(_state.Negative, param1, param2); break;
case 0x18: Branch(_state.Overflow, param1, param2); break;
case 0x1C: WAIT(); break;
case 0x20: NOP();
break; //???
case 0x24: Skip(param1, param2);
break;
case 0x28: JSR(true, param1, param2);
break;
case 0x2C: JSR(_state.Zero, param1, param2);
break;
case 0x20: NOP(); break; //???
case 0x24: Skip(param1, param2); break;
case 0x28: JSR(true, param1, param2); break;
case 0x2C: JSR(_state.Zero, param1, param2); break;
case 0x30: JSR(_state.Carry, param1, param2);
break;
case 0x34: JSR(_state.Negative, param1, param2);
break;
case 0x38: JSR(_state.Overflow, param1, param2);
break;
case 0x3C: RTS();
break;
case 0x30: JSR(_state.Carry, param1, param2); break;
case 0x34: JSR(_state.Negative, param1, param2); break;
case 0x38: JSR(_state.Overflow, param1, param2); break;
case 0x3C: RTS(); break;
case 0x40: IncMar();
break;
case 0x44: NOP();
break; //???
case 0x48: CMPR(param1, param2);
break;
case 0x4C: CMPR_Imm(param1, param2);
break;
case 0x40: IncMar(); break;
case 0x44: NOP(); break; //???
case 0x48: CMPR(param1, param2); break;
case 0x4C: CMPR_Imm(param1, param2); break;
case 0x50: CMP(param1, param2);
break;
case 0x54: CMP_Imm(param1, param2);
break;
case 0x58: SignExtend(param1);
break;
case 0x5C: NOP();
break; //???
case 0x50: CMP(param1, param2); break;
case 0x54: CMP_Imm(param1, param2); break;
case 0x58: SignExtend(param1); break;
case 0x5C: NOP(); break; //???
case 0x60: Load(param1, param2);
break;
case 0x64: Load_Imm(param1, param2);
break;
case 0x68: ReadRam(param1);
break;
case 0x6C: ReadRam_Imm(param1, param2);
break;
case 0x60: Load(param1, param2); break;
case 0x64: Load_Imm(param1, param2); break;
case 0x68: ReadRam(param1); break;
case 0x6C: ReadRam_Imm(param1, param2); break;
case 0x70: ReadRom();
break;
case 0x74: ReadRom_Imm((param1 << 8) | param2);
break;
case 0x78: NOP();
break;
case 0x7C: LoadP(param1, param2);
break;
case 0x70: ReadRom(); break;
case 0x74: ReadRom_Imm((param1 << 8) | param2); break;
case 0x78: NOP(); break;
case 0x7C: LoadP(param1, param2); break;
case 0x80: ADD(param1, param2);
break;
case 0x84: ADD_Imm(param1, param2);
break;
case 0x88: SUBR(param1, param2);
break;
case 0x8C: SUBR_Imm(param1, param2);
break;
case 0x80: ADD(param1, param2); break;
case 0x84: ADD_Imm(param1, param2); break;
case 0x88: SUBR(param1, param2); break;
case 0x8C: SUBR_Imm(param1, param2); break;
case 0x90: SUB(param1, param2);
break;
case 0x94: SUB_Imm(param1, param2);
break;
case 0x98: SMUL(param2);
break;
case 0x9C: SMUL_Imm(param2);
break;
case 0x90: SUB(param1, param2); break;
case 0x94: SUB_Imm(param1, param2); break;
case 0x98: SMUL(param2); break;
case 0x9C: SMUL_Imm(param2); break;
case 0xA0: XNOR(param1, param2);
break;
case 0xA4: XNOR_Imm(param1, param2);
break;
case 0xA8: XOR(param1, param2);
break;
case 0xAC: XOR_Imm(param1, param2);
break;
case 0xA0: XNOR(param1, param2); break;
case 0xA4: XNOR_Imm(param1, param2); break;
case 0xA8: XOR(param1, param2); break;
case 0xAC: XOR_Imm(param1, param2); break;
case 0xB0: AND(param1, param2);
break;
case 0xB4: AND_Imm(param1, param2);
break;
case 0xB8: OR(param1, param2);
break;
case 0xBC: OR_Imm(param1, param2);
break;
case 0xB0: AND(param1, param2); break;
case 0xB4: AND_Imm(param1, param2); break;
case 0xB8: OR(param1, param2); break;
case 0xBC: OR_Imm(param1, param2); break;
case 0xC0: SHR(param2);
break;
case 0xC4: SHR_Imm(param2);
break;
case 0xC8: ASR(param2);
break;
case 0xCC: ASR_Imm(param2);
break;
case 0xC0: SHR(param2); break;
case 0xC4: SHR_Imm(param2); break;
case 0xC8: ASR(param2); break;
case 0xCC: ASR_Imm(param2); break;
case 0xD0: ROR(param2);
break;
case 0xD4: ROR_Imm(param2);
break;
case 0xD8: SHL(param2);
break;
case 0xDC: SHL_Imm(param2);
break;
case 0xD0: ROR(param2); break;
case 0xD4: ROR_Imm(param2); break;
case 0xD8: SHL(param2); break;
case 0xDC: SHL_Imm(param2); break;
case 0xE0: Store(param1, param2);
break;
case 0xE4: NOP();
break; //???
case 0xE8: WriteRam(param1);
break;
case 0xEC: WriteRam_Imm(param1, param2);
break;
case 0xE0: Store(param1, param2); break;
case 0xE4: NOP(); break; //???
case 0xE8: WriteRam(param1); break;
case 0xEC: WriteRam_Imm(param1, param2); break;
case 0xF0: Swap(param2 & 0x0F);
break;
case 0xF4: NOP();
break; //???
case 0xF8: NOP();
break; //???
case 0xFC: Stop();
break;
case 0xF0: Swap(param2 & 0x0F); break;
case 0xF4: NOP(); break; //???
case 0xF8: NOP(); break; //???
case 0xFC: Stop(); break;
}
Step(1);
@ -166,8 +101,7 @@ void Cx4::Exec(uint16_t opCode)
uint32_t Cx4::GetSourceValue(uint8_t src)
{
switch (src & 0x7F)
{
switch(src & 0x7F) {
case 0x00: return _state.A;
case 0x01: return (_state.Mult >> 24) & 0xFFFFFF;
case 0x02: return _state.Mult & 0xFFFFFF;
@ -210,38 +144,22 @@ uint32_t Cx4::GetSourceValue(uint8_t src)
case 0x5E: return 0x000100;
case 0x5F: return 0x00FEFF;
case 0x60:
case 0x70: return _state.Regs[0];
case 0x61:
case 0x71: return _state.Regs[1];
case 0x62:
case 0x72: return _state.Regs[2];
case 0x63:
case 0x73: return _state.Regs[3];
case 0x64:
case 0x74: return _state.Regs[4];
case 0x65:
case 0x75: return _state.Regs[5];
case 0x66:
case 0x76: return _state.Regs[6];
case 0x67:
case 0x77: return _state.Regs[7];
case 0x68:
case 0x78: return _state.Regs[8];
case 0x69:
case 0x79: return _state.Regs[9];
case 0x6A:
case 0x7A: return _state.Regs[10];
case 0x6B:
case 0x7B: return _state.Regs[11];
case 0x6C:
case 0x7C: return _state.Regs[12];
case 0x6D:
case 0x7D: return _state.Regs[13];
case 0x6E:
case 0x7E: return _state.Regs[14];
case 0x6F:
case 0x7F: return _state.Regs[15];
case 0x60: case 0x70: return _state.Regs[0];
case 0x61: case 0x71: return _state.Regs[1];
case 0x62: case 0x72: return _state.Regs[2];
case 0x63: case 0x73: return _state.Regs[3];
case 0x64: case 0x74: return _state.Regs[4];
case 0x65: case 0x75: return _state.Regs[5];
case 0x66: case 0x76: return _state.Regs[6];
case 0x67: case 0x77: return _state.Regs[7];
case 0x68: case 0x78: return _state.Regs[8];
case 0x69: case 0x79: return _state.Regs[9];
case 0x6A: case 0x7A: return _state.Regs[10];
case 0x6B: case 0x7B: return _state.Regs[11];
case 0x6C: case 0x7C: return _state.Regs[12];
case 0x6D: case 0x7D: return _state.Regs[13];
case 0x6E: case 0x7E: return _state.Regs[14];
case 0x6F: case 0x7F: return _state.Regs[15];
}
return 0;
@ -250,30 +168,21 @@ uint32_t Cx4::GetSourceValue(uint8_t src)
void Cx4::WriteRegister(uint8_t reg, uint32_t value)
{
value &= 0xFFFFFF;
switch (reg & 0x7F)
{
case 0x01: _state.Mult = (_state.Mult & 0xFFFFFF) | (value << 24);
break;
case 0x02: _state.Mult = (_state.Mult & 0xFFFFFF000000) | value;
break;
case 0x03: _state.MemoryDataReg = value;
break;
case 0x08: _state.RomBuffer = value;
break;
switch(reg & 0x7F) {
case 0x01: _state.Mult = (_state.Mult & 0xFFFFFF) | (value << 24); break;
case 0x02: _state.Mult = (_state.Mult & 0xFFFFFF000000) | value; break;
case 0x03: _state.MemoryDataReg = value; break;
case 0x08: _state.RomBuffer = value; break;
case 0x0C:
_state.RamBuffer[0] = value;
_state.RamBuffer[1] = value >> 8;
_state.RamBuffer[2] = value >> 16;
break;
case 0x13: _state.MemoryAddressReg = value;
break;
case 0x1C: _state.DataPointerReg = value;
break;
case 0x20: _state.PC = value;
break;
case 0x28: _state.P = (value & 0x7FFF);
break;
case 0x13: _state.MemoryAddressReg = value; break;
case 0x1C: _state.DataPointerReg = value; break;
case 0x20: _state.PC = value; break;
case 0x28: _state.P = (value & 0x7FFF); break;
case 0x2E:
_state.Bus.Enabled = true;
@ -289,54 +198,22 @@ void Cx4::WriteRegister(uint8_t reg, uint32_t value)
_state.Bus.Address = _state.MemoryAddressReg;
break;
case 0x60:
case 0x70: _state.Regs[0] = value;
break;
case 0x61:
case 0x71: _state.Regs[1] = value;
break;
case 0x62:
case 0x72: _state.Regs[2] = value;
break;
case 0x63:
case 0x73: _state.Regs[3] = value;
break;
case 0x64:
case 0x74: _state.Regs[4] = value;
break;
case 0x65:
case 0x75: _state.Regs[5] = value;
break;
case 0x66:
case 0x76: _state.Regs[6] = value;
break;
case 0x67:
case 0x77: _state.Regs[7] = value;
break;
case 0x68:
case 0x78: _state.Regs[8] = value;
break;
case 0x69:
case 0x79: _state.Regs[9] = value;
break;
case 0x6A:
case 0x7a: _state.Regs[10] = value;
break;
case 0x6B:
case 0x7b: _state.Regs[11] = value;
break;
case 0x6C:
case 0x7c: _state.Regs[12] = value;
break;
case 0x6D:
case 0x7d: _state.Regs[13] = value;
break;
case 0x6E:
case 0x7e: _state.Regs[14] = value;
break;
case 0x6F:
case 0x7f: _state.Regs[15] = value;
break;
case 0x60: case 0x70: _state.Regs[0] = value; break;
case 0x61: case 0x71: _state.Regs[1] = value; break;
case 0x62: case 0x72: _state.Regs[2] = value; break;
case 0x63: case 0x73: _state.Regs[3] = value; break;
case 0x64: case 0x74: _state.Regs[4] = value; break;
case 0x65: case 0x75: _state.Regs[5] = value; break;
case 0x66: case 0x76: _state.Regs[6] = value; break;
case 0x67: case 0x77: _state.Regs[7] = value; break;
case 0x68: case 0x78: _state.Regs[8] = value; break;
case 0x69: case 0x79: _state.Regs[9] = value; break;
case 0x6A: case 0x7a: _state.Regs[10] = value; break;
case 0x6B: case 0x7b: _state.Regs[11] = value; break;
case 0x6C: case 0x7c: _state.Regs[12] = value; break;
case 0x6D: case 0x7d: _state.Regs[13] = value; break;
case 0x6E: case 0x7e: _state.Regs[14] = value; break;
case 0x6F: case 0x7f: _state.Regs[15] = value; break;
}
}
@ -351,8 +228,7 @@ void Cx4::NOP()
void Cx4::WAIT()
{
if (_state.Bus.Enabled)
{
if(_state.Bus.Enabled) {
Step(_state.Bus.DelayCycles);
}
}
@ -360,24 +236,17 @@ void Cx4::WAIT()
void Cx4::Skip(uint8_t flagToCheck, uint8_t skipIfSet)
{
bool skip;
switch (flagToCheck)
{
switch(flagToCheck) {
default:
case 0: skip = _state.Overflow == (skipIfSet & 0x01);
break;
case 1: skip = _state.Carry == (skipIfSet & 0x01);
break;
case 2: skip = _state.Zero == (skipIfSet & 0x01);
break;
case 3: skip = _state.Negative == (skipIfSet & 0x01);
break;
case 0: skip = _state.Overflow == (skipIfSet & 0x01); break;
case 1: skip = _state.Carry == (skipIfSet & 0x01); break;
case 2: skip = _state.Zero == (skipIfSet & 0x01); break;
case 3: skip = _state.Negative == (skipIfSet & 0x01); break;
}
if (skip)
{
if(skip) {
_state.PC++;
if (_state.PC == 0)
{
if(_state.PC == 0) {
SwitchCachePage();
}
Step(1);
@ -386,10 +255,8 @@ void Cx4::Skip(uint8_t flagToCheck, uint8_t skipIfSet)
void Cx4::Branch(bool branch, uint8_t far, uint8_t dest)
{
if (branch)
{
if (far)
{
if(branch) {
if(far) {
_state.PB = _state.P;
}
_state.PC = dest;
@ -399,11 +266,9 @@ void Cx4::Branch(bool branch, uint8_t far, uint8_t dest)
void Cx4::JSR(bool branch, uint8_t far, uint8_t dest)
{
if (branch)
{
if(branch) {
PushPC();
if (far)
{
if(far) {
_state.PB = _state.P;
}
_state.PC = dest;
@ -483,14 +348,11 @@ void Cx4::CMP_Imm(uint8_t shift, uint8_t imm)
void Cx4::SignExtend(uint8_t mode)
{
if (mode == 1)
{
if(mode == 1) {
_state.A = ((uint32_t)(int8_t)_state.A) & 0xFFFFFF;
_state.Negative = _state.A & 0x800000;
_state.Zero = _state.A == 0;
}
else if (mode == 2)
{
} else if(mode == 2) {
_state.A = ((uint32_t)(int16_t)_state.A) & 0xFFFFFF;
_state.Negative = _state.A & 0x800000;
_state.Zero = _state.A == 0;
@ -499,31 +361,21 @@ void Cx4::SignExtend(uint8_t mode)
void Cx4::Load(uint8_t dest, uint8_t src)
{
switch (dest)
{
case 0: _state.A = GetSourceValue(src);
break;
case 1: _state.MemoryDataReg = GetSourceValue(src);
break;
case 2: _state.MemoryAddressReg = GetSourceValue(src);
break;
case 3: _state.P = GetSourceValue(src) & 0x7FFF;
break;
switch(dest) {
case 0: _state.A = GetSourceValue(src); break;
case 1: _state.MemoryDataReg = GetSourceValue(src); break;
case 2: _state.MemoryAddressReg = GetSourceValue(src); break;
case 3: _state.P = GetSourceValue(src) & 0x7FFF; break;
}
}
void Cx4::Load_Imm(uint8_t dest, uint8_t imm)
{
switch (dest)
{
case 0: _state.A = imm;
break;
case 1: _state.MemoryDataReg = imm;
break;
case 2: _state.MemoryAddressReg = imm;
break;
case 3: _state.P = imm;
break;
switch(dest) {
case 0: _state.A = imm; break;
case 1: _state.MemoryDataReg = imm; break;
case 2: _state.MemoryAddressReg = imm; break;
case 3: _state.P = imm; break;
}
}
@ -619,8 +471,7 @@ void Cx4::XNOR_Imm(uint8_t shift, uint8_t imm)
void Cx4::SHR(uint8_t src)
{
uint8_t shift = GetSourceValue(src) & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA(_state.A >> shift);
}
SetZeroNegativeFlags();
@ -629,8 +480,7 @@ void Cx4::SHR(uint8_t src)
void Cx4::SHR_Imm(uint8_t imm)
{
uint8_t shift = imm & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA(_state.A >> shift);
}
SetZeroNegativeFlags();
@ -639,8 +489,7 @@ void Cx4::SHR_Imm(uint8_t imm)
void Cx4::ASR(uint8_t src)
{
uint8_t shift = GetSourceValue(src) & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA((((int32_t)_state.A << 8) >> 8) >> shift);
}
SetZeroNegativeFlags();
@ -649,8 +498,7 @@ void Cx4::ASR(uint8_t src)
void Cx4::ASR_Imm(uint8_t imm)
{
uint8_t shift = imm & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA((((int32_t)_state.A << 8) >> 8) >> shift);
}
SetZeroNegativeFlags();
@ -659,8 +507,7 @@ void Cx4::ASR_Imm(uint8_t imm)
void Cx4::SHL(uint8_t src)
{
uint8_t shift = GetSourceValue(src) & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA(_state.A << shift);
}
SetZeroNegativeFlags();
@ -669,8 +516,7 @@ void Cx4::SHL(uint8_t src)
void Cx4::SHL_Imm(uint8_t imm)
{
uint8_t shift = imm & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA(_state.A << shift);
}
SetZeroNegativeFlags();
@ -679,8 +525,7 @@ void Cx4::SHL_Imm(uint8_t imm)
void Cx4::ROR(uint8_t src)
{
uint8_t shift = GetSourceValue(src) & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA((_state.A >> shift) | (_state.A << (24 - shift)));
}
SetZeroNegativeFlags();
@ -689,8 +534,7 @@ void Cx4::ROR(uint8_t src)
void Cx4::ROR_Imm(uint8_t imm)
{
uint8_t shift = imm & 0x1F;
if (shift < 24)
{
if(shift < 24) {
SetA((_state.A >> shift) | (_state.A << (24 - shift)));
}
SetZeroNegativeFlags();
@ -708,14 +552,12 @@ void Cx4::ReadRom_Imm(uint16_t imm)
void Cx4::ReadRam(uint8_t byteIndex)
{
if (byteIndex >= 3)
{
if(byteIndex >= 3) {
return;
}
uint16_t addr = _state.A & 0xFFF;
if (addr >= 0xC00)
{
if(addr >= 0xC00) {
addr -= 0x400;
}
@ -724,14 +566,12 @@ void Cx4::ReadRam(uint8_t byteIndex)
void Cx4::ReadRam_Imm(uint8_t byteIndex, uint8_t imm)
{
if (byteIndex >= 3)
{
if(byteIndex >= 3) {
return;
}
uint16_t addr = (_state.DataPointerReg + imm) & 0xFFF;
if (addr >= 0xC00)
{
if(addr >= 0xC00) {
addr -= 0x400;
}
_state.RamBuffer[byteIndex] = _dataRam[addr];
@ -739,14 +579,12 @@ void Cx4::ReadRam_Imm(uint8_t byteIndex, uint8_t imm)
void Cx4::WriteRam(uint8_t byteIndex)
{
if (byteIndex >= 3)
{
if(byteIndex >= 3) {
return;
}
uint16_t addr = _state.A & 0xFFF;
if (addr >= 0xC00)
{
if(addr >= 0xC00) {
addr -= 0x400;
}
@ -755,14 +593,12 @@ void Cx4::WriteRam(uint8_t byteIndex)
void Cx4::WriteRam_Imm(uint8_t byteIndex, uint8_t imm)
{
if (byteIndex >= 3)
{
if(byteIndex >= 3) {
return;
}
uint16_t addr = (_state.DataPointerReg + imm) & 0xFFF;
if (addr >= 0xC00)
{
if(addr >= 0xC00) {
addr -= 0x400;
}
_dataRam[addr] = _state.RamBuffer[byteIndex];
@ -770,12 +606,9 @@ void Cx4::WriteRam_Imm(uint8_t byteIndex, uint8_t imm)
void Cx4::LoadP(uint8_t byteIndex, uint8_t imm)
{
switch (byteIndex)
{
case 0: _state.P = (_state.P & 0x7F00) | imm;
break;
case 1: _state.P = (_state.P & 0xFF) | ((imm & 0x7F) << 8);
break;
switch(byteIndex) {
case 0: _state.P = (_state.P & 0x7F00) | imm; break;
case 1: _state.P = (_state.P & 0xFF) | ((imm & 0x7F) << 8); break;
default: break; //nop
}
}
@ -789,12 +622,9 @@ void Cx4::Swap(uint8_t reg)
void Cx4::Store(uint8_t src, uint8_t dst)
{
switch (src)
{
case 0: WriteRegister(dst, _state.A);
break;
case 1: WriteRegister(dst, _state.MemoryDataReg);
break;
switch(src) {
case 0: WriteRegister(dst, _state.A); break;
case 1: WriteRegister(dst, _state.MemoryDataReg); break;
default: break; //nop
}
}
@ -802,8 +632,7 @@ void Cx4::Store(uint8_t src, uint8_t dst)
void Cx4::Stop()
{
_state.Stopped = true;
if (!_state.IrqDisabled)
{
if(!_state.IrqDisabled) {
_state.IrqFlag = true;
_cpu->SetIrqSource(IrqSource::Coprocessor);
}
@ -816,132 +645,68 @@ void Cx4::IncMar()
//Data ROM that contains precalculated math lookup tables for sines, cosines, division, etc.
const uint32_t _dataRom[1024] = {
0xFFFFFF, 0x800000, 0x400000, 0x2AAAAA, 0x200000, 0x199999, 0x155555, 0x124924, 0x100000, 0x0E38E3, 0x0CCCCC,
0x0BA2E8, 0x0AAAAA, 0x09D89D, 0x092492, 0x088888,
0x080000, 0x078787, 0x071C71, 0x06BCA1, 0x066666, 0x061861, 0x05D174, 0x0590B2, 0x055555, 0x051EB8, 0x04EC4E,
0x04BDA1, 0x049249, 0x0469EE, 0x044444, 0x042108,
0x040000, 0x03E0F8, 0x03C3C3, 0x03A83A, 0x038E38, 0x03759F, 0x035E50, 0x034834, 0x033333, 0x031F38, 0x030C30,
0x02FA0B, 0x02E8BA, 0x02D82D, 0x02C859, 0x02B931,
0x02AAAA, 0x029CBC, 0x028F5C, 0x028282, 0x027627, 0x026A43, 0x025ED0, 0x0253C8, 0x024924, 0x023EE0, 0x0234F7,
0x022B63, 0x022222, 0x02192E, 0x021084, 0x020820,
0x020000, 0x01F81F, 0x01F07C, 0x01E913, 0x01E1E1, 0x01DAE6, 0x01D41D, 0x01CD85, 0x01C71C, 0x01C0E0, 0x01BACF,
0x01B4E8, 0x01AF28, 0x01A98E, 0x01A41A, 0x019EC8,
0x019999, 0x01948B, 0x018F9C, 0x018ACB, 0x018618, 0x018181, 0x017D05, 0x0178A4, 0x01745D, 0x01702E, 0x016C16,
0x016816, 0x01642C, 0x016058, 0x015C98, 0x0158ED,
0x015555, 0x0151D0, 0x014E5E, 0x014AFD, 0x0147AE, 0x01446F, 0x014141, 0x013E22, 0x013B13, 0x013813, 0x013521,
0x01323E, 0x012F68, 0x012C9F, 0x0129E4, 0x012735,
0x012492, 0x0121FB, 0x011F70, 0x011CF0, 0x011A7B, 0x011811, 0x0115B1, 0x01135C, 0x011111, 0x010ECF, 0x010C97,
0x010A68, 0x010842, 0x010624, 0x010410, 0x010204,
0x010000, 0x00FE03, 0x00FC0F, 0x00FA23, 0x00F83E, 0x00F660, 0x00F489, 0x00F2B9, 0x00F0F0, 0x00EF2E, 0x00ED73,
0x00EBBD, 0x00EA0E, 0x00E865, 0x00E6C2, 0x00E525,
0x00E38E, 0x00E1FC, 0x00E070, 0x00DEE9, 0x00DD67, 0x00DBEB, 0x00DA74, 0x00D901, 0x00D794, 0x00D62B, 0x00D4C7,
0x00D368, 0x00D20D, 0x00D0B6, 0x00CF64, 0x00CE16,
0x00CCCC, 0x00CB87, 0x00CA45, 0x00C907, 0x00C7CE, 0x00C698, 0x00C565, 0x00C437, 0x00C30C, 0x00C1E4, 0x00C0C0,
0x00BFA0, 0x00BE82, 0x00BD69, 0x00BC52, 0x00BB3E,
0x00BA2E, 0x00B921, 0x00B817, 0x00B70F, 0x00B60B, 0x00B509, 0x00B40B, 0x00B30F, 0x00B216, 0x00B11F, 0x00B02C,
0x00AF3A, 0x00AE4C, 0x00AD60, 0x00AC76, 0x00AB8F,
0x00AAAA, 0x00A9C8, 0x00A8E8, 0x00A80A, 0x00A72F, 0x00A655, 0x00A57E, 0x00A4A9, 0x00A3D7, 0x00A306, 0x00A237,
0x00A16B, 0x00A0A0, 0x009FD8, 0x009F11, 0x009E4C,
0x009D89, 0x009CC8, 0x009C09, 0x009B4C, 0x009A90, 0x0099D7, 0x00991F, 0x009868, 0x0097B4, 0x009701, 0x00964F,
0x0095A0, 0x0094F2, 0x009445, 0x00939A, 0x0092F1,
0x009249, 0x0091A2, 0x0090FD, 0x00905A, 0x008FB8, 0x008F17, 0x008E78, 0x008DDA, 0x008D3D, 0x008CA2, 0x008C08,
0x008B70, 0x008AD8, 0x008A42, 0x0089AE, 0x00891A,
0x008888, 0x0087F7, 0x008767, 0x0086D9, 0x00864B, 0x0085BF, 0x008534, 0x0084A9, 0x008421, 0x008399, 0x008312,
0x00828C, 0x008208, 0x008184, 0x008102, 0x008080,
0x000000, 0x100000, 0x16A09E, 0x1BB67A, 0x200000, 0x23C6EF, 0x27311C, 0x2A54FF, 0x2D413C, 0x300000, 0x3298B0,
0x3510E5, 0x376CF5, 0x39B056, 0x3BDDD4, 0x3DF7BD,
0x400000, 0x41F83D, 0x43E1DB, 0x45BE0C, 0x478DDE, 0x49523A, 0x4B0BF1, 0x4CBBB9, 0x4E6238, 0x500000, 0x519595,
0x532370, 0x54A9FE, 0x5629A2, 0x57A2B7, 0x591590,
0x5A8279, 0x5BE9BA, 0x5D4B94, 0x5EA843, 0x600000, 0x6152FE, 0x62A170, 0x63EB83, 0x653160, 0x667332, 0x67B11D,
0x68EB44, 0x6A21CA, 0x6B54CD, 0x6C846C, 0x6DB0C2,
0x6ED9EB, 0x700000, 0x712318, 0x72434A, 0x7360AD, 0x747B54, 0x759354, 0x76A8BF, 0x77BBA8, 0x78CC1F, 0x79DA34,
0x7AE5F9, 0x7BEF7A, 0x7CF6C8, 0x7DFBEF, 0x7EFEFD,
0x800000, 0x80FF01, 0x81FC0F, 0x82F734, 0x83F07B, 0x84E7EE, 0x85DD98, 0x86D182, 0x87C3B6, 0x88B43D, 0x89A31F,
0x8A9066, 0x8B7C19, 0x8C6641, 0x8D4EE4, 0x8E360B,
0x8F1BBC, 0x900000, 0x90E2DB, 0x91C456, 0x92A475, 0x938341, 0x9460BD, 0x953CF1, 0x9617E2, 0x96F196, 0x97CA11,
0x98A159, 0x997773, 0x9A4C64, 0x9B2031, 0x9BF2DE,
0x9CC470, 0x9D94EB, 0x9E6454, 0x9F32AF, 0xA00000, 0xA0CC4A, 0xA19792, 0xA261DC, 0xA32B2A, 0xA3F382, 0xA4BAE6,
0xA5815A, 0xA646E1, 0xA70B7E, 0xA7CF35, 0xA89209,
0xA953FD, 0xAA1513, 0xAAD550, 0xAB94B4, 0xAC5345, 0xAD1103, 0xADCDF2, 0xAE8A15, 0xAF456E, 0xB00000, 0xB0B9CC,
0xB172D6, 0xB22B20, 0xB2E2AC, 0xB3997C, 0xB44F93,
0xB504F3, 0xB5B99D, 0xB66D95, 0xB720DC, 0xB7D375, 0xB88560, 0xB936A0, 0xB9E738, 0xBA9728, 0xBB4673, 0xBBF51A,
0xBCA320, 0xBD5086, 0xBDFD4E, 0xBEA979, 0xBF5509,
0xC00000, 0xC0AA5F, 0xC15428, 0xC1FD5C, 0xC2A5FD, 0xC34E0D, 0xC3F58C, 0xC49C7D, 0xC542E1, 0xC5E8B8, 0xC68E05,
0xC732C9, 0xC7D706, 0xC87ABB, 0xC91DEB, 0xC9C098,
0xCA62C1, 0xCB0469, 0xCBA591, 0xCC463A, 0xCCE664, 0xCD8612, 0xCE2544, 0xCEC3FC, 0xCF623A, 0xD00000, 0xD09D4E,
0xD13A26, 0xD1D689, 0xD27277, 0xD30DF3, 0xD3A8FC,
0xD44394, 0xD4DDBC, 0xD57774, 0xD610BE, 0xD6A99B, 0xD7420B, 0xD7DA0F, 0xD871A9, 0xD908D8, 0xD99F9F, 0xDA35FE,
0xDACBF5, 0xDB6185, 0xDBF6B0, 0xDC8B76, 0xDD1FD8,
0xDDB3D7, 0xDE4773, 0xDEDAAD, 0xDF6D86, 0xE00000, 0xE09219, 0xE123D4, 0xE1B530, 0xE24630, 0xE2D6D2, 0xE36719,
0xE3F704, 0xE48694, 0xE515CB, 0xE5A4A8, 0xE6332D,
0xE6C15A, 0xE74F2F, 0xE7DCAD, 0xE869D6, 0xE8F6A9, 0xE98326, 0xEA0F50, 0xEA9B26, 0xEB26A8, 0xEBB1D9, 0xEC3CB7,
0xECC743, 0xED517F, 0xEDDB6A, 0xEE6506, 0xEEEE52,
0xEF7750, 0xF00000, 0xF08861, 0xF11076, 0xF1983E, 0xF21FBA, 0xF2A6EA, 0xF32DCF, 0xF3B469, 0xF43AB9, 0xF4C0C0,
0xF5467D, 0xF5CBF2, 0xF6511E, 0xF6D602, 0xF75A9F,
0xF7DEF5, 0xF86305, 0xF8E6CE, 0xF96A52, 0xF9ED90, 0xFA708A, 0xFAF33F, 0xFB75B1, 0xFBF7DF, 0xFC79CA, 0xFCFB72,
0xFD7CD8, 0xFDFDFB, 0xFE7EDE, 0xFEFF7F, 0xFF7FDF,
0x000000, 0x03243A, 0x064855, 0x096C32, 0x0C8FB2, 0x0FB2B7, 0x12D520, 0x15F6D0, 0x1917A6, 0x1C3785, 0x1F564E,
0x2273E1, 0x259020, 0x28AAED, 0x2BC428, 0x2EDBB3,
0x31F170, 0x350540, 0x381704, 0x3B269F, 0x3E33F2, 0x413EE0, 0x444749, 0x474D10, 0x4A5018, 0x4D5043, 0x504D72,
0x534789, 0x563E69, 0x5931F7, 0x5C2214, 0x5F0EA4,
0x61F78A, 0x64DCA9, 0x67BDE5, 0x6A9B20, 0x6D7440, 0x704927, 0x7319BA, 0x75E5DD, 0x78AD74, 0x7B7065, 0x7E2E93,
0x80E7E4, 0x839C3C, 0x864B82, 0x88F59A, 0x8B9A6B,
0x8E39D9, 0x90D3CC, 0x93682A, 0x95F6D9, 0x987FBF, 0x9B02C5, 0x9D7FD1, 0x9FF6CA, 0xA26799, 0xA4D224, 0xA73655,
0xA99414, 0xABEB49, 0xAE3BDD, 0xB085BA, 0xB2C8C9,
0xB504F3, 0xB73A22, 0xB96841, 0xBB8F3A, 0xBDAEF9, 0xBFC767, 0xC1D870, 0xC3E200, 0xC5E403, 0xC7DE65, 0xC9D112,
0xCBBBF7, 0xCD9F02, 0xCF7A1F, 0xD14D3D, 0xD31848,
0xD4DB31, 0xD695E4, 0xD84852, 0xD9F269, 0xDB941A, 0xDD2D53, 0xDEBE05, 0xE04621, 0xE1C597, 0xE33C59, 0xE4AA59,
0xE60F87, 0xE76BD7, 0xE8BF3B, 0xEA09A6, 0xEB4B0B,
0xEC835E, 0xEDB293, 0xEED89D, 0xEFF573, 0xF10908, 0xF21352, 0xF31447, 0xF40BDD, 0xF4FA0A, 0xF5DEC6, 0xF6BA07,
0xF78BC5, 0xF853F7, 0xF91297, 0xF9C79D, 0xFA7301,
0xFB14BE, 0xFBACCD, 0xFC3B27, 0xFCBFC9, 0xFD3AAB, 0xFDABCB, 0xFE1323, 0xFE70AF, 0xFEC46D, 0xFF0E57, 0xFF4E6D,
0xFF84AB, 0xFFB10F, 0xFFD397, 0xFFEC43, 0xFFFB10,
0x000000, 0x00A2F9, 0x0145F6, 0x01E8F8, 0x028C01, 0x032F14, 0x03D234, 0x047564, 0x0518A5, 0x05BBFB, 0x065F68,
0x0702EF, 0x07A692, 0x084A54, 0x08EE38, 0x099240,
0x0A366E, 0x0ADAC7, 0x0B7F4C, 0x0C2401, 0x0CC8E7, 0x0D6E02, 0x0E1355, 0x0EB8E3, 0x0F5EAE, 0x1004B9, 0x10AB08,
0x11519E, 0x11F87D, 0x129FA9, 0x134725, 0x13EEF4,
0x149719, 0x153F99, 0x15E875, 0x1691B2, 0x173B53, 0x17E55C, 0x188FD1, 0x193AB4, 0x19E60A, 0x1A91D8, 0x1B3E20,
0x1BEAE7, 0x1C9831, 0x1D4602, 0x1DF45F, 0x1EA34C,
0x1F52CE, 0x2002EA, 0x20B3A3, 0x216500, 0x221705, 0x22C9B8, 0x237D1E, 0x24313C, 0x24E618, 0x259BB9, 0x265224,
0x27095F, 0x27C171, 0x287A61, 0x293436, 0x29EEF6,
0x2AAAAA, 0x2B6759, 0x2C250A, 0x2CE3C7, 0x2DA398, 0x2E6485, 0x2F2699, 0x2FE9DC, 0x30AE59, 0x31741B, 0x323B2C,
0x330398, 0x33CD6B, 0x3498B1, 0x356578, 0x3633CE,
0x3703C1, 0x37D560, 0x38A8BB, 0x397DE4, 0x3A54EC, 0x3B2DE6, 0x3C08E6, 0x3CE601, 0x3DC54D, 0x3EA6E3, 0x3F8ADC,
0x407152, 0x415A62, 0x42462C, 0x4334D0, 0x442671,
0x451B37, 0x46134A, 0x470ED6, 0x480E0C, 0x491120, 0x4A184C, 0x4B23CD, 0x4C33EA, 0x4D48EC, 0x4E6327, 0x4F82F9,
0x50A8C9, 0x51D50A, 0x53083F, 0x5442FC, 0x5585EA,
0x56D1CC, 0x582782, 0x598815, 0x5AF4BC, 0x5C6EED, 0x5DF86C, 0x5F9369, 0x6142A3, 0x6309A5, 0x64ED1E, 0x66F381,
0x692617, 0x6B9322, 0x6E52A5, 0x71937C, 0x75CEB4,
0x000000, 0x000324, 0x000648, 0x00096D, 0x000C93, 0x000FBA, 0x0012E2, 0x00160B, 0x001936, 0x001C63, 0x001F93,
0x0022C4, 0x0025F9, 0x002930, 0x002C6B, 0x002FA9,
0x0032EB, 0x003632, 0x00397C, 0x003CCB, 0x00401F, 0x004379, 0x0046D8, 0x004A3D, 0x004DA8, 0x005119, 0x005492,
0x005811, 0x005B99, 0x005F28, 0x0062C0, 0x006660,
0x006A09, 0x006DBC, 0x00717A, 0x007541, 0x007914, 0x007CF2, 0x0080DC, 0x0084D2, 0x0088D5, 0x008CE6, 0x009105,
0x009533, 0x009970, 0x009DBE, 0x00A21C, 0x00A68B,
0x00AB0D, 0x00AFA2, 0x00B44B, 0x00B909, 0x00BDDC, 0x00C2C6, 0x00C7C8, 0x00CCE3, 0x00D218, 0x00D767, 0x00DCD3,
0x00E25D, 0x00E806, 0x00EDCF, 0x00F3BB, 0x00F9CA,
0x010000, 0x01065C, 0x010CE2, 0x011394, 0x011A73, 0x012183, 0x0128C6, 0x01303E, 0x0137EF, 0x013FDC, 0x014808,
0x015077, 0x01592D, 0x01622D, 0x016B7D, 0x017522,
0x017F21, 0x018980, 0x019444, 0x019F76, 0x01AB1C, 0x01B73E, 0x01C3E7, 0x01D11F, 0x01DEF1, 0x01ED69, 0x01FC95,
0x020C83, 0x021D44, 0x022EE9, 0x024186, 0x025533,
0x026A09, 0x028025, 0x0297A7, 0x02B0B5, 0x02CB78, 0x02E823, 0x0306EC, 0x032815, 0x034BEB, 0x0372C6, 0x039D10,
0x03CB47, 0x03FE02, 0x0435F7, 0x047405, 0x04B93F,
0x0506FF, 0x055EF9, 0x05C35D, 0x063709, 0x06BDCF, 0x075CE6, 0x081B97, 0x09046D, 0x0A2736, 0x0B9CC6, 0x0D8E81,
0x1046E9, 0x145AFF, 0x1B2671, 0x28BC48, 0x517BB5,
0xFFFFFF, 0xFFFB10, 0xFFEC43, 0xFFD397, 0xFFB10F, 0xFF84AB, 0xFF4E6D, 0xFF0E57, 0xFEC46D, 0xFE70AF, 0xFE1323,
0xFDABCB, 0xFD3AAB, 0xFCBFC9, 0xFC3B27, 0xFBACCD,
0xFB14BE, 0xFA7301, 0xF9C79D, 0xF91297, 0xF853F7, 0xF78BC5, 0xF6BA07, 0xF5DEC6, 0xF4FA0A, 0xF40BDD, 0xF31447,
0xF21352, 0xF10908, 0xEFF573, 0xEED89D, 0xEDB293,
0xEC835E, 0xEB4B0B, 0xEA09A6, 0xE8BF3B, 0xE76BD7, 0xE60F87, 0xE4AA59, 0xE33C59, 0xE1C597, 0xE04621, 0xDEBE05,
0xDD2D53, 0xDB941A, 0xD9F269, 0xD84852, 0xD695E4,
0xD4DB31, 0xD31848, 0xD14D3D, 0xCF7A1F, 0xCD9F02, 0xCBBBF7, 0xC9D112, 0xC7DE65, 0xC5E403, 0xC3E200, 0xC1D870,
0xBFC767, 0xBDAEF9, 0xBB8F3A, 0xB96841, 0xB73A22,
0xB504F3, 0xB2C8C9, 0xB085BA, 0xAE3BDD, 0xABEB49, 0xA99414, 0xA73655, 0xA4D224, 0xA26799, 0x9FF6CA, 0x9D7FD1,
0x9B02C5, 0x987FBF, 0x95F6D9, 0x93682A, 0x90D3CC,
0x8E39D9, 0x8B9A6B, 0x88F59A, 0x864B82, 0x839C3C, 0x80E7E4, 0x7E2E93, 0x7B7065, 0x78AD74, 0x75E5DD, 0x7319BA,
0x704927, 0x6D7440, 0x6A9B20, 0x67BDE5, 0x64DCA9,
0x61F78A, 0x5F0EA4, 0x5C2214, 0x5931F7, 0x563E69, 0x534789, 0x504D72, 0x4D5043, 0x4A5018, 0x474D10, 0x444749,
0x413EE0, 0x3E33F2, 0x3B269F, 0x381704, 0x350540,
0x31F170, 0x2EDBB3, 0x2BC428, 0x28AAED, 0x259020, 0x2273E1, 0x1F564E, 0x1C3785, 0x1917A6, 0x15F6D0, 0x12D520,
0x0FB2B7, 0x0C8FB2, 0x096C32, 0x064855, 0x03243A
0xFFFFFF, 0x800000, 0x400000, 0x2AAAAA, 0x200000, 0x199999, 0x155555, 0x124924, 0x100000, 0x0E38E3, 0x0CCCCC, 0x0BA2E8, 0x0AAAAA, 0x09D89D, 0x092492, 0x088888,
0x080000, 0x078787, 0x071C71, 0x06BCA1, 0x066666, 0x061861, 0x05D174, 0x0590B2, 0x055555, 0x051EB8, 0x04EC4E, 0x04BDA1, 0x049249, 0x0469EE, 0x044444, 0x042108,
0x040000, 0x03E0F8, 0x03C3C3, 0x03A83A, 0x038E38, 0x03759F, 0x035E50, 0x034834, 0x033333, 0x031F38, 0x030C30, 0x02FA0B, 0x02E8BA, 0x02D82D, 0x02C859, 0x02B931,
0x02AAAA, 0x029CBC, 0x028F5C, 0x028282, 0x027627, 0x026A43, 0x025ED0, 0x0253C8, 0x024924, 0x023EE0, 0x0234F7, 0x022B63, 0x022222, 0x02192E, 0x021084, 0x020820,
0x020000, 0x01F81F, 0x01F07C, 0x01E913, 0x01E1E1, 0x01DAE6, 0x01D41D, 0x01CD85, 0x01C71C, 0x01C0E0, 0x01BACF, 0x01B4E8, 0x01AF28, 0x01A98E, 0x01A41A, 0x019EC8,
0x019999, 0x01948B, 0x018F9C, 0x018ACB, 0x018618, 0x018181, 0x017D05, 0x0178A4, 0x01745D, 0x01702E, 0x016C16, 0x016816, 0x01642C, 0x016058, 0x015C98, 0x0158ED,
0x015555, 0x0151D0, 0x014E5E, 0x014AFD, 0x0147AE, 0x01446F, 0x014141, 0x013E22, 0x013B13, 0x013813, 0x013521, 0x01323E, 0x012F68, 0x012C9F, 0x0129E4, 0x012735,
0x012492, 0x0121FB, 0x011F70, 0x011CF0, 0x011A7B, 0x011811, 0x0115B1, 0x01135C, 0x011111, 0x010ECF, 0x010C97, 0x010A68, 0x010842, 0x010624, 0x010410, 0x010204,
0x010000, 0x00FE03, 0x00FC0F, 0x00FA23, 0x00F83E, 0x00F660, 0x00F489, 0x00F2B9, 0x00F0F0, 0x00EF2E, 0x00ED73, 0x00EBBD, 0x00EA0E, 0x00E865, 0x00E6C2, 0x00E525,
0x00E38E, 0x00E1FC, 0x00E070, 0x00DEE9, 0x00DD67, 0x00DBEB, 0x00DA74, 0x00D901, 0x00D794, 0x00D62B, 0x00D4C7, 0x00D368, 0x00D20D, 0x00D0B6, 0x00CF64, 0x00CE16,
0x00CCCC, 0x00CB87, 0x00CA45, 0x00C907, 0x00C7CE, 0x00C698, 0x00C565, 0x00C437, 0x00C30C, 0x00C1E4, 0x00C0C0, 0x00BFA0, 0x00BE82, 0x00BD69, 0x00BC52, 0x00BB3E,
0x00BA2E, 0x00B921, 0x00B817, 0x00B70F, 0x00B60B, 0x00B509, 0x00B40B, 0x00B30F, 0x00B216, 0x00B11F, 0x00B02C, 0x00AF3A, 0x00AE4C, 0x00AD60, 0x00AC76, 0x00AB8F,
0x00AAAA, 0x00A9C8, 0x00A8E8, 0x00A80A, 0x00A72F, 0x00A655, 0x00A57E, 0x00A4A9, 0x00A3D7, 0x00A306, 0x00A237, 0x00A16B, 0x00A0A0, 0x009FD8, 0x009F11, 0x009E4C,
0x009D89, 0x009CC8, 0x009C09, 0x009B4C, 0x009A90, 0x0099D7, 0x00991F, 0x009868, 0x0097B4, 0x009701, 0x00964F, 0x0095A0, 0x0094F2, 0x009445, 0x00939A, 0x0092F1,
0x009249, 0x0091A2, 0x0090FD, 0x00905A, 0x008FB8, 0x008F17, 0x008E78, 0x008DDA, 0x008D3D, 0x008CA2, 0x008C08, 0x008B70, 0x008AD8, 0x008A42, 0x0089AE, 0x00891A,
0x008888, 0x0087F7, 0x008767, 0x0086D9, 0x00864B, 0x0085BF, 0x008534, 0x0084A9, 0x008421, 0x008399, 0x008312, 0x00828C, 0x008208, 0x008184, 0x008102, 0x008080,
0x000000, 0x100000, 0x16A09E, 0x1BB67A, 0x200000, 0x23C6EF, 0x27311C, 0x2A54FF, 0x2D413C, 0x300000, 0x3298B0, 0x3510E5, 0x376CF5, 0x39B056, 0x3BDDD4, 0x3DF7BD,
0x400000, 0x41F83D, 0x43E1DB, 0x45BE0C, 0x478DDE, 0x49523A, 0x4B0BF1, 0x4CBBB9, 0x4E6238, 0x500000, 0x519595, 0x532370, 0x54A9FE, 0x5629A2, 0x57A2B7, 0x591590,
0x5A8279, 0x5BE9BA, 0x5D4B94, 0x5EA843, 0x600000, 0x6152FE, 0x62A170, 0x63EB83, 0x653160, 0x667332, 0x67B11D, 0x68EB44, 0x6A21CA, 0x6B54CD, 0x6C846C, 0x6DB0C2,
0x6ED9EB, 0x700000, 0x712318, 0x72434A, 0x7360AD, 0x747B54, 0x759354, 0x76A8BF, 0x77BBA8, 0x78CC1F, 0x79DA34, 0x7AE5F9, 0x7BEF7A, 0x7CF6C8, 0x7DFBEF, 0x7EFEFD,
0x800000, 0x80FF01, 0x81FC0F, 0x82F734, 0x83F07B, 0x84E7EE, 0x85DD98, 0x86D182, 0x87C3B6, 0x88B43D, 0x89A31F, 0x8A9066, 0x8B7C19, 0x8C6641, 0x8D4EE4, 0x8E360B,
0x8F1BBC, 0x900000, 0x90E2DB, 0x91C456, 0x92A475, 0x938341, 0x9460BD, 0x953CF1, 0x9617E2, 0x96F196, 0x97CA11, 0x98A159, 0x997773, 0x9A4C64, 0x9B2031, 0x9BF2DE,
0x9CC470, 0x9D94EB, 0x9E6454, 0x9F32AF, 0xA00000, 0xA0CC4A, 0xA19792, 0xA261DC, 0xA32B2A, 0xA3F382, 0xA4BAE6, 0xA5815A, 0xA646E1, 0xA70B7E, 0xA7CF35, 0xA89209,
0xA953FD, 0xAA1513, 0xAAD550, 0xAB94B4, 0xAC5345, 0xAD1103, 0xADCDF2, 0xAE8A15, 0xAF456E, 0xB00000, 0xB0B9CC, 0xB172D6, 0xB22B20, 0xB2E2AC, 0xB3997C, 0xB44F93,
0xB504F3, 0xB5B99D, 0xB66D95, 0xB720DC, 0xB7D375, 0xB88560, 0xB936A0, 0xB9E738, 0xBA9728, 0xBB4673, 0xBBF51A, 0xBCA320, 0xBD5086, 0xBDFD4E, 0xBEA979, 0xBF5509,
0xC00000, 0xC0AA5F, 0xC15428, 0xC1FD5C, 0xC2A5FD, 0xC34E0D, 0xC3F58C, 0xC49C7D, 0xC542E1, 0xC5E8B8, 0xC68E05, 0xC732C9, 0xC7D706, 0xC87ABB, 0xC91DEB, 0xC9C098,
0xCA62C1, 0xCB0469, 0xCBA591, 0xCC463A, 0xCCE664, 0xCD8612, 0xCE2544, 0xCEC3FC, 0xCF623A, 0xD00000, 0xD09D4E, 0xD13A26, 0xD1D689, 0xD27277, 0xD30DF3, 0xD3A8FC,
0xD44394, 0xD4DDBC, 0xD57774, 0xD610BE, 0xD6A99B, 0xD7420B, 0xD7DA0F, 0xD871A9, 0xD908D8, 0xD99F9F, 0xDA35FE, 0xDACBF5, 0xDB6185, 0xDBF6B0, 0xDC8B76, 0xDD1FD8,
0xDDB3D7, 0xDE4773, 0xDEDAAD, 0xDF6D86, 0xE00000, 0xE09219, 0xE123D4, 0xE1B530, 0xE24630, 0xE2D6D2, 0xE36719, 0xE3F704, 0xE48694, 0xE515CB, 0xE5A4A8, 0xE6332D,
0xE6C15A, 0xE74F2F, 0xE7DCAD, 0xE869D6, 0xE8F6A9, 0xE98326, 0xEA0F50, 0xEA9B26, 0xEB26A8, 0xEBB1D9, 0xEC3CB7, 0xECC743, 0xED517F, 0xEDDB6A, 0xEE6506, 0xEEEE52,
0xEF7750, 0xF00000, 0xF08861, 0xF11076, 0xF1983E, 0xF21FBA, 0xF2A6EA, 0xF32DCF, 0xF3B469, 0xF43AB9, 0xF4C0C0, 0xF5467D, 0xF5CBF2, 0xF6511E, 0xF6D602, 0xF75A9F,
0xF7DEF5, 0xF86305, 0xF8E6CE, 0xF96A52, 0xF9ED90, 0xFA708A, 0xFAF33F, 0xFB75B1, 0xFBF7DF, 0xFC79CA, 0xFCFB72, 0xFD7CD8, 0xFDFDFB, 0xFE7EDE, 0xFEFF7F, 0xFF7FDF,
0x000000, 0x03243A, 0x064855, 0x096C32, 0x0C8FB2, 0x0FB2B7, 0x12D520, 0x15F6D0, 0x1917A6, 0x1C3785, 0x1F564E, 0x2273E1, 0x259020, 0x28AAED, 0x2BC428, 0x2EDBB3,
0x31F170, 0x350540, 0x381704, 0x3B269F, 0x3E33F2, 0x413EE0, 0x444749, 0x474D10, 0x4A5018, 0x4D5043, 0x504D72, 0x534789, 0x563E69, 0x5931F7, 0x5C2214, 0x5F0EA4,
0x61F78A, 0x64DCA9, 0x67BDE5, 0x6A9B20, 0x6D7440, 0x704927, 0x7319BA, 0x75E5DD, 0x78AD74, 0x7B7065, 0x7E2E93, 0x80E7E4, 0x839C3C, 0x864B82, 0x88F59A, 0x8B9A6B,
0x8E39D9, 0x90D3CC, 0x93682A, 0x95F6D9, 0x987FBF, 0x9B02C5, 0x9D7FD1, 0x9FF6CA, 0xA26799, 0xA4D224, 0xA73655, 0xA99414, 0xABEB49, 0xAE3BDD, 0xB085BA, 0xB2C8C9,
0xB504F3, 0xB73A22, 0xB96841, 0xBB8F3A, 0xBDAEF9, 0xBFC767, 0xC1D870, 0xC3E200, 0xC5E403, 0xC7DE65, 0xC9D112, 0xCBBBF7, 0xCD9F02, 0xCF7A1F, 0xD14D3D, 0xD31848,
0xD4DB31, 0xD695E4, 0xD84852, 0xD9F269, 0xDB941A, 0xDD2D53, 0xDEBE05, 0xE04621, 0xE1C597, 0xE33C59, 0xE4AA59, 0xE60F87, 0xE76BD7, 0xE8BF3B, 0xEA09A6, 0xEB4B0B,
0xEC835E, 0xEDB293, 0xEED89D, 0xEFF573, 0xF10908, 0xF21352, 0xF31447, 0xF40BDD, 0xF4FA0A, 0xF5DEC6, 0xF6BA07, 0xF78BC5, 0xF853F7, 0xF91297, 0xF9C79D, 0xFA7301,
0xFB14BE, 0xFBACCD, 0xFC3B27, 0xFCBFC9, 0xFD3AAB, 0xFDABCB, 0xFE1323, 0xFE70AF, 0xFEC46D, 0xFF0E57, 0xFF4E6D, 0xFF84AB, 0xFFB10F, 0xFFD397, 0xFFEC43, 0xFFFB10,
0x000000, 0x00A2F9, 0x0145F6, 0x01E8F8, 0x028C01, 0x032F14, 0x03D234, 0x047564, 0x0518A5, 0x05BBFB, 0x065F68, 0x0702EF, 0x07A692, 0x084A54, 0x08EE38, 0x099240,
0x0A366E, 0x0ADAC7, 0x0B7F4C, 0x0C2401, 0x0CC8E7, 0x0D6E02, 0x0E1355, 0x0EB8E3, 0x0F5EAE, 0x1004B9, 0x10AB08, 0x11519E, 0x11F87D, 0x129FA9, 0x134725, 0x13EEF4,
0x149719, 0x153F99, 0x15E875, 0x1691B2, 0x173B53, 0x17E55C, 0x188FD1, 0x193AB4, 0x19E60A, 0x1A91D8, 0x1B3E20, 0x1BEAE7, 0x1C9831, 0x1D4602, 0x1DF45F, 0x1EA34C,
0x1F52CE, 0x2002EA, 0x20B3A3, 0x216500, 0x221705, 0x22C9B8, 0x237D1E, 0x24313C, 0x24E618, 0x259BB9, 0x265224, 0x27095F, 0x27C171, 0x287A61, 0x293436, 0x29EEF6,
0x2AAAAA, 0x2B6759, 0x2C250A, 0x2CE3C7, 0x2DA398, 0x2E6485, 0x2F2699, 0x2FE9DC, 0x30AE59, 0x31741B, 0x323B2C, 0x330398, 0x33CD6B, 0x3498B1, 0x356578, 0x3633CE,
0x3703C1, 0x37D560, 0x38A8BB, 0x397DE4, 0x3A54EC, 0x3B2DE6, 0x3C08E6, 0x3CE601, 0x3DC54D, 0x3EA6E3, 0x3F8ADC, 0x407152, 0x415A62, 0x42462C, 0x4334D0, 0x442671,
0x451B37, 0x46134A, 0x470ED6, 0x480E0C, 0x491120, 0x4A184C, 0x4B23CD, 0x4C33EA, 0x4D48EC, 0x4E6327, 0x4F82F9, 0x50A8C9, 0x51D50A, 0x53083F, 0x5442FC, 0x5585EA,
0x56D1CC, 0x582782, 0x598815, 0x5AF4BC, 0x5C6EED, 0x5DF86C, 0x5F9369, 0x6142A3, 0x6309A5, 0x64ED1E, 0x66F381, 0x692617, 0x6B9322, 0x6E52A5, 0x71937C, 0x75CEB4,
0x000000, 0x000324, 0x000648, 0x00096D, 0x000C93, 0x000FBA, 0x0012E2, 0x00160B, 0x001936, 0x001C63, 0x001F93, 0x0022C4, 0x0025F9, 0x002930, 0x002C6B, 0x002FA9,
0x0032EB, 0x003632, 0x00397C, 0x003CCB, 0x00401F, 0x004379, 0x0046D8, 0x004A3D, 0x004DA8, 0x005119, 0x005492, 0x005811, 0x005B99, 0x005F28, 0x0062C0, 0x006660,
0x006A09, 0x006DBC, 0x00717A, 0x007541, 0x007914, 0x007CF2, 0x0080DC, 0x0084D2, 0x0088D5, 0x008CE6, 0x009105, 0x009533, 0x009970, 0x009DBE, 0x00A21C, 0x00A68B,
0x00AB0D, 0x00AFA2, 0x00B44B, 0x00B909, 0x00BDDC, 0x00C2C6, 0x00C7C8, 0x00CCE3, 0x00D218, 0x00D767, 0x00DCD3, 0x00E25D, 0x00E806, 0x00EDCF, 0x00F3BB, 0x00F9CA,
0x010000, 0x01065C, 0x010CE2, 0x011394, 0x011A73, 0x012183, 0x0128C6, 0x01303E, 0x0137EF, 0x013FDC, 0x014808, 0x015077, 0x01592D, 0x01622D, 0x016B7D, 0x017522,
0x017F21, 0x018980, 0x019444, 0x019F76, 0x01AB1C, 0x01B73E, 0x01C3E7, 0x01D11F, 0x01DEF1, 0x01ED69, 0x01FC95, 0x020C83, 0x021D44, 0x022EE9, 0x024186, 0x025533,
0x026A09, 0x028025, 0x0297A7, 0x02B0B5, 0x02CB78, 0x02E823, 0x0306EC, 0x032815, 0x034BEB, 0x0372C6, 0x039D10, 0x03CB47, 0x03FE02, 0x0435F7, 0x047405, 0x04B93F,
0x0506FF, 0x055EF9, 0x05C35D, 0x063709, 0x06BDCF, 0x075CE6, 0x081B97, 0x09046D, 0x0A2736, 0x0B9CC6, 0x0D8E81, 0x1046E9, 0x145AFF, 0x1B2671, 0x28BC48, 0x517BB5,
0xFFFFFF, 0xFFFB10, 0xFFEC43, 0xFFD397, 0xFFB10F, 0xFF84AB, 0xFF4E6D, 0xFF0E57, 0xFEC46D, 0xFE70AF, 0xFE1323, 0xFDABCB, 0xFD3AAB, 0xFCBFC9, 0xFC3B27, 0xFBACCD,
0xFB14BE, 0xFA7301, 0xF9C79D, 0xF91297, 0xF853F7, 0xF78BC5, 0xF6BA07, 0xF5DEC6, 0xF4FA0A, 0xF40BDD, 0xF31447, 0xF21352, 0xF10908, 0xEFF573, 0xEED89D, 0xEDB293,
0xEC835E, 0xEB4B0B, 0xEA09A6, 0xE8BF3B, 0xE76BD7, 0xE60F87, 0xE4AA59, 0xE33C59, 0xE1C597, 0xE04621, 0xDEBE05, 0xDD2D53, 0xDB941A, 0xD9F269, 0xD84852, 0xD695E4,
0xD4DB31, 0xD31848, 0xD14D3D, 0xCF7A1F, 0xCD9F02, 0xCBBBF7, 0xC9D112, 0xC7DE65, 0xC5E403, 0xC3E200, 0xC1D870, 0xBFC767, 0xBDAEF9, 0xBB8F3A, 0xB96841, 0xB73A22,
0xB504F3, 0xB2C8C9, 0xB085BA, 0xAE3BDD, 0xABEB49, 0xA99414, 0xA73655, 0xA4D224, 0xA26799, 0x9FF6CA, 0x9D7FD1, 0x9B02C5, 0x987FBF, 0x95F6D9, 0x93682A, 0x90D3CC,
0x8E39D9, 0x8B9A6B, 0x88F59A, 0x864B82, 0x839C3C, 0x80E7E4, 0x7E2E93, 0x7B7065, 0x78AD74, 0x75E5DD, 0x7319BA, 0x704927, 0x6D7440, 0x6A9B20, 0x67BDE5, 0x64DCA9,
0x61F78A, 0x5F0EA4, 0x5C2214, 0x5931F7, 0x563E69, 0x534789, 0x504D72, 0x4D5043, 0x4A5018, 0x474D10, 0x444749, 0x413EE0, 0x3E33F2, 0x3B269F, 0x381704, 0x350540,
0x31F170, 0x2EDBB3, 0x2BC428, 0x28AAED, 0x259020, 0x2273E1, 0x1F564E, 0x1C3785, 0x1917A6, 0x15F6D0, 0x12D520, 0x0FB2B7, 0x0C8FB2, 0x096C32, 0x064855, 0x03243A
};

View file

@ -22,8 +22,8 @@ Cx4::Cx4(Console* console) : BaseCoprocessor(SnesMemoryType::Register)
console->GetSettings()->InitializeRam(_dataRam, Cx4::DataRamSize);
auto& prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers();
auto& saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers();
auto &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers();
auto &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers();
MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings();
//PRG ROM
@ -62,56 +62,36 @@ void Cx4::Run()
{
uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
while (_state.CycleCount < targetCycle)
{
if (_state.Locked)
{
while(_state.CycleCount < targetCycle) {
if(_state.Locked) {
Step(1);
}
else if (_state.Suspend.Enabled)
{
if (_state.Suspend.Duration == 0)
{
} else if(_state.Suspend.Enabled) {
if(_state.Suspend.Duration == 0) {
Step(1);
}
else
{
} else {
Step(1);
_state.Suspend.Duration--;
if (_state.Suspend.Duration == 0)
{
if(_state.Suspend.Duration == 0) {
_state.Suspend.Enabled = false;
}
}
}
else if (_state.Cache.Enabled)
{
} else if(_state.Cache.Enabled) {
ProcessCache(targetCycle);
}
else if (_state.Dma.Enabled)
{
} else if(_state.Dma.Enabled) {
ProcessDma(targetCycle);
}
else if (_state.Stopped)
{
} else if(_state.Stopped) {
Step(targetCycle - _state.CycleCount);
}
else if (!ProcessCache(targetCycle))
{
if (!_state.Cache.Enabled)
{
} else if(!ProcessCache(targetCycle)) {
if(!_state.Cache.Enabled) {
//Cache operation required, but both caches are locked, stop
Stop();
}
}
else
{
} else {
uint16_t opCode = _prgRam[_state.Cache.Page][_state.PC];
_console->ProcessMemoryRead<CpuType::Cx4>(0, 0, MemoryOperationType::ExecOpCode);
_state.PC++;
if (_state.PC == 0)
{
if(_state.PC == 0) {
//If execution reached the end of the page, start loading the next page
//This must be done BEFORE running the instruction (otherwise a jump/branch to address 0 will trigger this)
SwitchCachePage();
@ -124,25 +104,19 @@ void Cx4::Run()
void Cx4::Step(uint64_t cycles)
{
if (_state.Bus.Enabled)
{
if (_state.Bus.DelayCycles > cycles)
{
if(_state.Bus.Enabled) {
if(_state.Bus.DelayCycles > cycles) {
_state.Bus.DelayCycles -= (uint8_t)cycles;
}
else
{
} else {
_state.Bus.Enabled = false;
_state.Bus.DelayCycles = 0;
if (_state.Bus.Reading)
{
if(_state.Bus.Reading) {
_state.MemoryDataReg = ReadCx4(_state.Bus.Address);
_state.Bus.Reading = false;
}
if (_state.Bus.Writing)
{
if(_state.Bus.Writing) {
WriteCx4(_state.Bus.Address, _state.MemoryDataReg);
_state.Bus.Writing = false;
}
@ -154,15 +128,13 @@ void Cx4::Step(uint64_t cycles)
void Cx4::SwitchCachePage()
{
if (_state.Cache.Page == 1)
{
if(_state.Cache.Page == 1) {
Stop();
return;
}
_state.Cache.Page = 1;
if (_state.Cache.Lock[1])
{
if(_state.Cache.Lock[1]) {
Stop();
return;
}
@ -170,8 +142,7 @@ void Cx4::SwitchCachePage()
_state.PB = _state.P;
uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
if (!ProcessCache(targetCycle) && !_state.Cache.Enabled)
{
if(!ProcessCache(targetCycle) && !_state.Cache.Enabled) {
Stop();
}
}
@ -180,10 +151,8 @@ bool Cx4::ProcessCache(uint64_t targetCycle)
{
uint32_t address = (_state.Cache.Base + (_state.PB << 9)) & 0xFFFFFF;
if (_state.Cache.Pos == 0)
{
if (_state.Cache.Address[_state.Cache.Page] == address)
{
if(_state.Cache.Pos == 0) {
if(_state.Cache.Address[_state.Cache.Page] == address) {
//Current cache page matches the needed address, keep using it
_state.Cache.Enabled = false;
return true;
@ -192,21 +161,18 @@ bool Cx4::ProcessCache(uint64_t targetCycle)
//Check if the other page matches
_state.Cache.Page ^= 1;
if (_state.Cache.Address[_state.Cache.Page] == address)
{
if(_state.Cache.Address[_state.Cache.Page] == address) {
//The other cache page matches, use it
_state.Cache.Enabled = false;
return true;
}
if (_state.Cache.Lock[_state.Cache.Page])
{
if(_state.Cache.Lock[_state.Cache.Page]) {
//If it's locked, use the other page
_state.Cache.Page ^= 1;
}
if (_state.Cache.Lock[_state.Cache.Page])
{
if(_state.Cache.Lock[_state.Cache.Page]) {
//The both pages are locked, and the cache is invalid, give up.
_state.Cache.Enabled = false;
return false;
@ -216,8 +182,7 @@ bool Cx4::ProcessCache(uint64_t targetCycle)
}
//Populate the cache
while (_state.Cache.Pos < 256)
{
while(_state.Cache.Pos < 256) {
uint8_t lsb = ReadCx4(address + (_state.Cache.Pos * 2));
Step(GetAccessDelay(address + (_state.Cache.Pos * 2)));
@ -227,14 +192,12 @@ bool Cx4::ProcessCache(uint64_t targetCycle)
_prgRam[_state.Cache.Page][_state.Cache.Pos] = (msb << 8) | lsb;
_state.Cache.Pos++;
if (_state.CycleCount > targetCycle)
{
if(_state.CycleCount > targetCycle) {
break;
}
}
if (_state.Cache.Pos >= 256)
{
if(_state.Cache.Pos >= 256) {
_state.Cache.Address[_state.Cache.Page] = address;
_state.Cache.Pos = 0;
_state.Cache.Enabled = false;
@ -247,16 +210,13 @@ bool Cx4::ProcessCache(uint64_t targetCycle)
void Cx4::ProcessDma(uint64_t targetCycle)
{
while (_state.Dma.Pos < _state.Dma.Length)
{
while(_state.Dma.Pos < _state.Dma.Length) {
uint32_t src = (_state.Dma.Source + _state.Dma.Pos) & 0xFFFFFF;
uint32_t dest = (_state.Dma.Dest + _state.Dma.Pos) & 0xFFFFFF;
IMemoryHandler* srcHandler = _mappings.GetHandler(src);
IMemoryHandler* destHandler = _mappings.GetHandler(dest);
if (!srcHandler || !destHandler || srcHandler->GetMemoryType() == destHandler->GetMemoryType() || destHandler->
GetMemoryType() == SnesMemoryType::PrgRom)
{
IMemoryHandler *srcHandler = _mappings.GetHandler(src);
IMemoryHandler *destHandler = _mappings.GetHandler(dest);
if(!srcHandler || !destHandler || srcHandler->GetMemoryType() == destHandler->GetMemoryType() || destHandler->GetMemoryType() == SnesMemoryType::PrgRom) {
//Invalid DMA, the chip is locked until it gets restarted by a write to $7F53
_state.Locked = true;
_state.Dma.Pos = 0;
@ -271,14 +231,12 @@ void Cx4::ProcessDma(uint64_t targetCycle)
WriteCx4(dest, value);
_state.Dma.Pos++;
if (_state.CycleCount > targetCycle)
{
if(_state.CycleCount > targetCycle) {
break;
}
}
if (_state.Dma.Pos >= _state.Dma.Length)
{
if(_state.Dma.Pos >= _state.Dma.Length) {
_state.Dma.Pos = 0;
_state.Dma.Enabled = false;
}
@ -287,12 +245,9 @@ void Cx4::ProcessDma(uint64_t targetCycle)
uint8_t Cx4::GetAccessDelay(uint32_t addr)
{
IMemoryHandler* handler = _mappings.GetHandler(addr);
if (handler->GetMemoryType() == SnesMemoryType::PrgRom)
{
if(handler->GetMemoryType() == SnesMemoryType::PrgRom) {
return 1 + _state.RomAccessDelay;
}
else if (handler->GetMemoryType() == SnesMemoryType::SaveRam)
{
} else if(handler->GetMemoryType() == SnesMemoryType::SaveRam) {
return 1 + _state.RamAccessDelay;
}
@ -302,8 +257,7 @@ uint8_t Cx4::GetAccessDelay(uint32_t addr)
uint8_t Cx4::ReadCx4(uint32_t addr)
{
IMemoryHandler* handler = _mappings.GetHandler(addr);
if (handler)
{
if(handler) {
uint8_t value = handler->Read(addr);
_console->ProcessMemoryRead<CpuType::Cx4>(addr, value, MemoryOperationType::Read);
return value;
@ -314,8 +268,7 @@ uint8_t Cx4::ReadCx4(uint32_t addr)
void Cx4::WriteCx4(uint32_t addr, uint8_t value)
{
IMemoryHandler* handler = _mappings.GetHandler(addr);
if (handler)
{
if(handler) {
_console->ProcessMemoryWrite<CpuType::Cx4>(addr, value, MemoryOperationType::Write);
handler->Write(addr, value);
}
@ -324,33 +277,23 @@ void Cx4::WriteCx4(uint32_t addr, uint8_t value)
uint8_t Cx4::Read(uint32_t addr)
{
addr = 0x7000 | (addr & 0xFFF);
if (addr <= 0x7BFF)
{
if(addr <= 0x7BFF) {
return _dataRam[addr & 0xFFF];
}
else if (addr >= 0x7F60 && addr <= 0x7F7F)
{
} else if(addr >= 0x7F60 && addr <= 0x7F7F) {
return _state.Vectors[addr & 0x1F];
}
else if ((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF))
{
} else if((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) {
addr &= 0x3F;
uint32_t& reg = _state.Regs[addr / 3];
switch (addr % 3)
{
uint32_t &reg = _state.Regs[addr / 3];
switch(addr % 3) {
case 0: return reg;
case 1: return reg >> 8;
case 2: return reg >> 16;
}
}
else if (addr >= 0x7F53 && addr <= 0x7F5F)
{
return (uint8_t)_state.Suspend.Enabled | ((uint8_t)_state.IrqFlag << 1) | ((uint8_t)IsRunning() << 6) | ((uint8_t)
IsBusy() << 7);
} else if(addr >= 0x7F53 && addr <= 0x7F5F) {
return (uint8_t)_state.Suspend.Enabled | ((uint8_t)_state.IrqFlag << 1) | ((uint8_t)IsRunning() << 6) | ((uint8_t)IsBusy() << 7);
}
switch (addr)
{
switch(addr) {
case 0x7F40: return _state.Dma.Source;
case 0x7F41: return _state.Dma.Source >> 8;
case 0x7F42: return _state.Dma.Source >> 16;
@ -379,90 +322,62 @@ void Cx4::Write(uint32_t addr, uint8_t value)
{
addr = 0x7000 | (addr & 0xFFF);
if (addr <= 0x7BFF)
{
if(addr <= 0x7BFF) {
_dataRam[addr & 0xFFF] = value;
return;
}
if (addr >= 0x7F60 && addr <= 0x7F7F)
{
if(addr >= 0x7F60 && addr <= 0x7F7F) {
_state.Vectors[addr & 0x1F] = value;
}
else if ((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF))
{
} else if((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) {
addr &= 0x3F;
uint32_t& reg = _state.Regs[addr / 3];
switch (addr % 3)
{
case 0: reg = (reg & 0xFFFF00) | value;
break;
case 1: reg = (reg & 0xFF00FF) | (value << 8);
break;
case 2: reg = (reg & 0x00FFFF) | (value << 16);
break;
uint32_t &reg = _state.Regs[addr / 3];
switch(addr % 3) {
case 0: reg = (reg & 0xFFFF00) | value; break;
case 1: reg = (reg & 0xFF00FF) | (value << 8); break;
case 2: reg = (reg & 0x00FFFF) | (value << 16); break;
}
}
else if (addr >= 0x7F55 && addr <= 0x7F5C)
{
} else if(addr >= 0x7F55 && addr <= 0x7F5C) {
_state.Suspend.Enabled = true;
_state.Suspend.Duration = (addr - 0x7F55) * 32;
}
else
{
switch (addr)
{
case 0x7F40: _state.Dma.Source = (_state.Dma.Source & 0xFFFF00) | value;
break;
case 0x7F41: _state.Dma.Source = (_state.Dma.Source & 0xFF00FF) | (value << 8);
break;
case 0x7F42: _state.Dma.Source = (_state.Dma.Source & 0x00FFFF) | (value << 16);
break;
case 0x7F43: _state.Dma.Length = (_state.Dma.Length & 0xFF00) | value;
break;
case 0x7F44: _state.Dma.Length = (_state.Dma.Length & 0x00FF) | (value << 8);
break;
case 0x7F45: _state.Dma.Dest = (_state.Dma.Dest & 0xFFFF00) | value;
break;
case 0x7F46: _state.Dma.Dest = (_state.Dma.Dest & 0xFF00FF) | (value << 8);
break;
} else {
switch(addr) {
case 0x7F40: _state.Dma.Source = (_state.Dma.Source & 0xFFFF00) | value; break;
case 0x7F41: _state.Dma.Source = (_state.Dma.Source & 0xFF00FF) | (value << 8); break;
case 0x7F42: _state.Dma.Source = (_state.Dma.Source & 0x00FFFF) | (value << 16); break;
case 0x7F43: _state.Dma.Length = (_state.Dma.Length & 0xFF00) | value; break;
case 0x7F44: _state.Dma.Length = (_state.Dma.Length & 0x00FF) | (value << 8); break;
case 0x7F45: _state.Dma.Dest = (_state.Dma.Dest & 0xFFFF00) | value; break;
case 0x7F46: _state.Dma.Dest = (_state.Dma.Dest & 0xFF00FF) | (value << 8); break;
case 0x7F47:
_state.Dma.Dest = (_state.Dma.Dest & 0x00FFFF) | (value << 16);
if (_state.Stopped)
{
if(_state.Stopped) {
_state.Dma.Enabled = true;
}
break;
case 0x7F48:
_state.Cache.Page = value & 0x01;
if (_state.Stopped)
{
if(_state.Stopped) {
_state.Cache.Enabled = true;
}
break;
case 0x7F49: _state.Cache.Base = (_state.Cache.Base & 0xFFFF00) | value;
break;
case 0x7F4A: _state.Cache.Base = (_state.Cache.Base & 0xFF00FF) | (value << 8);
break;
case 0x7F4B: _state.Cache.Base = (_state.Cache.Base & 0x00FFFF) | (value << 16);
break;
case 0x7F49: _state.Cache.Base = (_state.Cache.Base & 0xFFFF00) | value; break;
case 0x7F4A: _state.Cache.Base = (_state.Cache.Base & 0xFF00FF) | (value << 8); break;
case 0x7F4B: _state.Cache.Base = (_state.Cache.Base & 0x00FFFF) | (value << 16); break;
case 0x7F4C:
_state.Cache.Lock[0] = (value & 0x01) != 0;
_state.Cache.Lock[1] = (value & 0x02) != 0;
break;
case 0x7F4D: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0xFF00) | value;
break;
case 0x7F4E: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0x00FF) | ((value & 0x7F) << 8);
break;
case 0x7F4D: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0xFF00) | value; break;
case 0x7F4E: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0x00FF) | ((value & 0x7F) << 8); break;
case 0x7F4F:
_state.Cache.ProgramCounter = value;
if (_state.Stopped)
{
if(_state.Stopped) {
_state.Stopped = false;
_state.PB = _state.Cache.ProgramBank;
_state.PC = _state.Cache.ProgramCounter;
@ -476,23 +391,20 @@ void Cx4::Write(uint32_t addr, uint8_t value)
case 0x7F51:
_state.IrqDisabled = value & 0x01;
if (_state.IrqDisabled)
{
if(_state.IrqDisabled) {
_state.IrqFlag = true;
_cpu->ClearIrqSource(IrqSource::Coprocessor);
}
break;
case 0x7F52: _state.SingleRom = (value & 0x01) != 0;
break;
case 0x7F52: _state.SingleRom = (value & 0x01) != 0; break;
case 0x7F53:
_state.Locked = false;
_state.Stopped = true;
break;
case 0x7F5D: _state.Suspend.Enabled = false;
break;
case 0x7F5D: _state.Suspend.Enabled = false; break;
case 0x7F5E:
//Clear IRQ flag in CX4, but keeps IRQ signal high
@ -512,19 +424,15 @@ bool Cx4::IsBusy()
return _state.Cache.Enabled || _state.Dma.Enabled || _state.Bus.DelayCycles > 0;
}
void Cx4::Serialize(Serializer& s)
void Cx4::Serialize(Serializer &s)
{
s.Stream(
_state.CycleCount, _state.PB, _state.PC, _state.A, _state.P, _state.SP, _state.Mult, _state.RomBuffer,
_state.RamBuffer[0], _state.RamBuffer[1], _state.RamBuffer[2], _state.MemoryDataReg, _state.MemoryAddressReg,
_state.DataPointerReg, _state.Negative, _state.Zero, _state.Carry, _state.Overflow, _state.IrqFlag,
_state.Stopped,
_state.Locked, _state.IrqDisabled, _state.SingleRom, _state.RamAccessDelay, _state.RomAccessDelay,
_state.Bus.Address,
_state.Bus.DelayCycles, _state.Bus.Enabled, _state.Bus.Reading, _state.Bus.Writing, _state.Dma.Dest,
_state.Dma.Enabled,
_state.Dma.Length, _state.Dma.Source, _state.Dma.Pos, _state.Suspend.Duration, _state.Suspend.Enabled,
_state.Cache.Enabled,
_state.DataPointerReg, _state.Negative, _state.Zero, _state.Carry, _state.Overflow, _state.IrqFlag, _state.Stopped,
_state.Locked, _state.IrqDisabled, _state.SingleRom, _state.RamAccessDelay, _state.RomAccessDelay, _state.Bus.Address,
_state.Bus.DelayCycles, _state.Bus.Enabled, _state.Bus.Reading, _state.Bus.Writing, _state.Dma.Dest, _state.Dma.Enabled,
_state.Dma.Length, _state.Dma.Source, _state.Dma.Pos, _state.Suspend.Duration, _state.Suspend.Enabled, _state.Cache.Enabled,
_state.Cache.Lock[0], _state.Cache.Lock[1], _state.Cache.Address[0], _state.Cache.Address[1], _state.Cache.Base,
_state.Cache.Page, _state.Cache.ProgramBank, _state.Cache.ProgramCounter, _state.Cache.Pos
);
@ -549,7 +457,7 @@ void Cx4::PeekBlock(uint32_t addr, uint8_t* output)
AddressInfo Cx4::GetAbsoluteAddress(uint32_t address)
{
return {-1, SnesMemoryType::Register};
return { -1, SnesMemoryType::Register };
}
MemoryMappings* Cx4::GetMemoryMappings()
@ -576,48 +484,31 @@ void Cx4::SetReg(Cx4Register reg, uint32_t value)
{
switch (reg)
{
case Cx4Register::Cx4Reg0:
case Cx4Register::Cx4Reg1:
case Cx4Register::Cx4Reg2:
case Cx4Register::Cx4Reg3:
case Cx4Register::Cx4Reg4:
case Cx4Register::Cx4Reg5:
case Cx4Register::Cx4Reg6:
case Cx4Register::Cx4Reg7:
case Cx4Register::Cx4Reg8:
case Cx4Register::Cx4Reg9:
case Cx4Register::Cx4Reg10:
case Cx4Register::Cx4Reg11:
case Cx4Register::Cx4Reg12:
case Cx4Register::Cx4Reg13:
case Cx4Register::Cx4Reg14:
case Cx4Register::Cx4Reg15:
case Cx4Register::Cx4Reg0: case Cx4Register::Cx4Reg1: case Cx4Register::Cx4Reg2: case Cx4Register::Cx4Reg3:
case Cx4Register::Cx4Reg4: case Cx4Register::Cx4Reg5: case Cx4Register::Cx4Reg6: case Cx4Register::Cx4Reg7:
case Cx4Register::Cx4Reg8: case Cx4Register::Cx4Reg9: case Cx4Register::Cx4Reg10: case Cx4Register::Cx4Reg11:
case Cx4Register::Cx4Reg12: case Cx4Register::Cx4Reg13: case Cx4Register::Cx4Reg14: case Cx4Register::Cx4Reg15:
_state.Regs[(static_cast<int>(reg) - static_cast<int>(Cx4Register::Cx4Reg0)) & 0x0F] = value & 0xFFFFFF; // 24-bit
break;
case Cx4Register::Cx4RegPB:
{
_state.PB = value & 0xFFFF;
}
break;
} break;
case Cx4Register::Cx4RegPC:
{
_state.PC = value & 0xFF;
}
break;
} break;
case Cx4Register::Cx4RegA:
{
_state.A = value & 0xFFFFFF; // 24-bit
}
break;
} break;
case Cx4Register::Cx4RegP:
{
_state.P = value & 0xFFFF;
}
break;
} break;
case Cx4Register::Cx4RegSP:
{
_state.SP = value & 0xFF;
}
break;
} break;
}
}

View file

@ -13,9 +13,9 @@ class Cx4 : public BaseCoprocessor
private:
static constexpr int DataRamSize = 0xC00;
Console* _console;
MemoryManager* _memoryManager;
Cpu* _cpu;
Console *_console;
MemoryManager *_memoryManager;
Cpu *_cpu;
MemoryMappings _mappings;
double _clockRatio;
@ -119,7 +119,7 @@ public:
uint8_t Read(uint32_t addr) override;
void Write(uint32_t addr, uint8_t value) override;
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
uint8_t Peek(uint32_t addr) override;
void PeekBlock(uint32_t addr, uint8_t* output) override;

View file

@ -42,23 +42,19 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
addr = (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF;
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation{(uint32_t)addr, value, type};
MemoryOperationInfo operation { (uint32_t)addr, value, type };
if (type == MemoryOperationType::ExecOpCode)
{
if(type == MemoryOperationType::ExecOpCode) {
AddressInfo opCodeHighAddr = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr + 1);
if (addressInfo.Type == SnesMemoryType::PrgRom)
{
if(addressInfo.Type == SnesMemoryType::PrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Cx4);
_codeDataLogger->SetFlags(addressInfo.Address + 1, CdlFlags::Code | CdlFlags::Cx4);
}
if (_traceLogger->IsCpuLogged(CpuType::Cx4) || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled))
{
if(_traceLogger->IsCpuLogged(CpuType::Cx4) || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {
_disassembler->BuildCache(addressInfo, 0, CpuType::Cx4);
if (_traceLogger->IsCpuLogged(CpuType::Cx4))
{
if(_traceLogger->IsCpuLogged(CpuType::Cx4)) {
DebugState debugState;
_debugger->GetState(debugState, true);
@ -69,18 +65,14 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevProgramCounter = addr;
if (_step->StepCount > 0)
{
if(_step->StepCount > 0) {
_step->StepCount--;
}
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
_memoryAccessCounter->ProcessMemoryExec(opCodeHighAddr, _memoryManager->GetMasterClock());
}
else
{
if (addressInfo.Type == SnesMemoryType::PrgRom)
{
} else {
if(addressInfo.Type == SnesMemoryType::PrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Cx4);
}
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
@ -92,7 +84,7 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation{(uint32_t)addr, value, type};
MemoryOperationInfo operation { (uint32_t)addr, value, type };
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
}
@ -106,10 +98,8 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type)
{
StepRequest step;
switch (type)
{
case StepType::Step: step.StepCount = stepCount;
break;
switch(type) {
case StepType::Step: step.StepCount = stepCount; break;
case StepType::StepOut:
case StepType::StepOver:

View file

@ -5,8 +5,7 @@
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.h"
void Cx4DisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings)
void Cx4DisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings *settings)
{
FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
@ -14,417 +13,197 @@ void Cx4DisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t me
uint8_t param1 = info.GetByteCode()[1] & 0x03;
uint8_t param2 = info.GetByteCode()[0] & 0xFF;
auto writeSrc = [&str, param2]() -> void
{
switch (param2 & 0x7F)
{
case 0x00: str.Write("A");
break;
case 0x01: str.Write("MULTH");
break;
case 0x02: str.Write("MULTL");
break;
case 0x03: str.Write("MDR");
break;
case 0x08: str.Write("ROM");
break;
case 0x0C: str.Write("RAM");
break;
case 0x13: str.Write("MAR");
break;
case 0x1C: str.Write("DPR");
break;
case 0x20: str.Write("PC");
break;
case 0x28: str.Write("P");
break;
auto writeSrc = [&str, param2]() -> void {
switch(param2 & 0x7F) {
case 0x00: str.Write("A"); break;
case 0x01: str.Write("MULTH"); break;
case 0x02: str.Write("MULTL"); break;
case 0x03: str.Write("MDR"); break;
case 0x08: str.Write("ROM"); break;
case 0x0C: str.Write("RAM"); break;
case 0x13: str.Write("MAR"); break;
case 0x1C: str.Write("DPR"); break;
case 0x20: str.Write("PC"); break;
case 0x28: str.Write("P"); break;
case 0x2E: str.Write("RDROM");
break;
case 0x2E: str.Write("RDROM"); break;
case 0x2F: str.Write("RDRAM");
break;
case 0x2F: str.Write("RDRAM"); break;
case 0x50: str.Write("#$000000");
break;
case 0x51: str.Write("#$FFFFFF");
break;
case 0x52: str.Write("#$00FF00");
break;
case 0x53: str.Write("#$FF0000");
break;
case 0x54: str.Write("#$00FFFF");
break;
case 0x55: str.Write("#$FFFF00");
break;
case 0x56: str.Write("#$800000");
break;
case 0x57: str.Write("#$7FFFFF");
break;
case 0x58: str.Write("#$008000");
break;
case 0x59: str.Write("#$007FFF");
break;
case 0x5A: str.Write("#$FF7FFF");
break;
case 0x5B: str.Write("#$FFFF7F");
break;
case 0x5C: str.Write("#$010000");
break;
case 0x5D: str.Write("#$FEFFFF");
break;
case 0x5E: str.Write("#$000100");
break;
case 0x5F: str.Write("#$00FEFF");
break;
case 0x50: str.Write("#$000000"); break;
case 0x51: str.Write("#$FFFFFF"); break;
case 0x52: str.Write("#$00FF00"); break;
case 0x53: str.Write("#$FF0000"); break;
case 0x54: str.Write("#$00FFFF"); break;
case 0x55: str.Write("#$FFFF00"); break;
case 0x56: str.Write("#$800000"); break;
case 0x57: str.Write("#$7FFFFF"); break;
case 0x58: str.Write("#$008000"); break;
case 0x59: str.Write("#$007FFF"); break;
case 0x5A: str.Write("#$FF7FFF"); break;
case 0x5B: str.Write("#$FFFF7F"); break;
case 0x5C: str.Write("#$010000"); break;
case 0x5D: str.Write("#$FEFFFF"); break;
case 0x5E: str.Write("#$000100"); break;
case 0x5F: str.Write("#$00FEFF"); break;
case 0x60:
case 0x70: str.Write("R0");
break;
case 0x61:
case 0x71: str.Write("R1");
break;
case 0x62:
case 0x72: str.Write("R2");
break;
case 0x63:
case 0x73: str.Write("R3");
break;
case 0x64:
case 0x74: str.Write("R4");
break;
case 0x65:
case 0x75: str.Write("R5");
break;
case 0x66:
case 0x76: str.Write("R6");
break;
case 0x67:
case 0x77: str.Write("R7");
break;
case 0x68:
case 0x78: str.Write("R8");
break;
case 0x69:
case 0x79: str.Write("R9");
break;
case 0x6A:
case 0x7A: str.Write("R10");
break;
case 0x6B:
case 0x7B: str.Write("R11");
break;
case 0x6C:
case 0x7C: str.Write("R12");
break;
case 0x6D:
case 0x7D: str.Write("R13");
break;
case 0x6E:
case 0x7E: str.Write("R14");
break;
case 0x6F:
case 0x7F: str.Write("R15");
break;
case 0x60: case 0x70: str.Write("R0"); break;
case 0x61: case 0x71: str.Write("R1"); break;
case 0x62: case 0x72: str.Write("R2"); break;
case 0x63: case 0x73: str.Write("R3"); break;
case 0x64: case 0x74: str.Write("R4"); break;
case 0x65: case 0x75: str.Write("R5"); break;
case 0x66: case 0x76: str.Write("R6"); break;
case 0x67: case 0x77: str.Write("R7"); break;
case 0x68: case 0x78: str.Write("R8"); break;
case 0x69: case 0x79: str.Write("R9"); break;
case 0x6A: case 0x7A: str.Write("R10"); break;
case 0x6B: case 0x7B: str.Write("R11"); break;
case 0x6C: case 0x7C: str.Write("R12"); break;
case 0x6D: case 0x7D: str.Write("R13"); break;
case 0x6E: case 0x7E: str.Write("R14"); break;
case 0x6F: case 0x7F: str.Write("R15"); break;
}
};
auto writeDest = [&str, param1]() -> void
{
switch (param1)
{
case 0: str.Write("A");
break;
case 1: str.Write("MDR");
break;
case 2: str.Write("MAR");
break;
case 3: str.Write("P");
break;
auto writeDest = [&str, param1]() -> void {
switch(param1) {
case 0: str.Write("A"); break;
case 1: str.Write("MDR"); break;
case 2: str.Write("MAR"); break;
case 3: str.Write("P"); break;
}
};
auto writeShiftedA = [&str, param1]() -> void
{
switch (param1)
{
case 0: str.Write("A");
break;
case 1: str.Write("(A << 1)");
break;
case 2: str.Write("(A << 8)");
break;
case 3: str.Write("(A << 16)");
break;
auto writeShiftedA = [&str, param1]() -> void {
switch(param1) {
case 0: str.Write("A"); break;
case 1: str.Write("(A << 1)"); break;
case 2: str.Write("(A << 8)"); break;
case 3: str.Write("(A << 16)"); break;
}
};
auto writeBranchTarget = [&str, param1, param2]() -> void
{
if (param1)
{
auto writeBranchTarget = [&str, param1, param2]() -> void {
if(param1) {
//Far jump
str.Write("P:");
}
str.WriteAll('$', HexUtilities::ToHex(param2));
};
switch (op)
{
case 0x00: str.Write("NOP");
break;
case 0x04: str.Write("???");
break;
case 0x08: str.Write("BRA ");
writeBranchTarget();
break;
case 0x0C: str.Write("BEQ ");
writeBranchTarget();
break;
switch(op) {
case 0x00: str.Write("NOP"); break;
case 0x04: str.Write("???"); break;
case 0x08: str.Write("BRA "); writeBranchTarget(); break;
case 0x0C: str.Write("BEQ "); writeBranchTarget(); break;
case 0x10: str.Write("BCS ");
writeBranchTarget();
break;
case 0x14: str.Write("BMI ");
writeBranchTarget();
break;
case 0x18: str.Write("BVS ");
writeBranchTarget();
break;
case 0x1C: str.Write("WAIT");
break;
case 0x10: str.Write("BCS "); writeBranchTarget(); break;
case 0x14: str.Write("BMI "); writeBranchTarget(); break;
case 0x18: str.Write("BVS "); writeBranchTarget(); break;
case 0x1C: str.Write("WAIT"); break;
case 0x20: str.Write("???");
break;
case 0x20: str.Write("???"); break;
case 0x24:
str.Write("SKIP");
switch (param1)
{
case 0: str.Write('V');
break;
case 1: str.Write('C');
break;
case 2: str.Write('Z');
break;
case 3: str.Write('N');
break;
switch(param1) {
case 0: str.Write('V'); break;
case 1: str.Write('C'); break;
case 2: str.Write('Z'); break;
case 3: str.Write('N'); break;
}
str.Write((param2 & 0x01) ? 'S' : 'C');
break;
case 0x28: str.Write("JSR ");
writeBranchTarget();
break;
case 0x2C: str.Write("JEQ ");
writeBranchTarget();
break;
case 0x28: str.Write("JSR "); writeBranchTarget(); break;
case 0x2C: str.Write("JEQ "); writeBranchTarget(); break;
case 0x30: str.Write("JCS ");
writeBranchTarget();
break;
case 0x34: str.Write("JMI ");
writeBranchTarget();
break;
case 0x38: str.Write("JVS ");
writeBranchTarget();
break;
case 0x3C: str.Write("RTS");
break;
case 0x30: str.Write("JCS "); writeBranchTarget(); break;
case 0x34: str.Write("JMI "); writeBranchTarget(); break;
case 0x38: str.Write("JVS "); writeBranchTarget(); break;
case 0x3C: str.Write("RTS"); break;
case 0x40: str.Write("INC MAR");
break;
case 0x44: str.Write("???");
break;
case 0x48: str.Write("CMPR ");
writeSrc();
str.Write(",");
writeShiftedA();
break;
case 0x4C: str.WriteAll("CMPR #$", HexUtilities::ToHex(param2));
str.Write(",");
writeShiftedA();
break;
case 0x40: str.Write("INC MAR"); break;
case 0x44: str.Write("???"); break;
case 0x48: str.Write("CMPR "); writeSrc(); str.Write(","); writeShiftedA(); break;
case 0x4C: str.WriteAll("CMPR #$", HexUtilities::ToHex(param2)); str.Write(","); writeShiftedA(); break;
case 0x50: str.Write("CMP ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0x54: str.WriteAll("CMP ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0x50: str.Write("CMP "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0x54: str.WriteAll("CMP "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0x58:
if (param1 == 1)
{
if(param1 == 1) {
str.Write("SXB");
}
else if (param1 == 2)
{
} else if(param1 == 2) {
str.Write("SXW");
}
else
{
} else {
str.Write("???");
}
break;
case 0x5C: str.Write("???");
break;
case 0x5C: str.Write("???"); break;
case 0x60: str.Write("LD ");
writeDest();
str.Write(",");
writeSrc();
break;
case 0x64: str.Write("LD ");
writeDest();
str.WriteAll(", #$", HexUtilities::ToHex(param2));
break;
case 0x60: str.Write("LD "); writeDest(); str.Write(","); writeSrc(); break;
case 0x64: str.Write("LD "); writeDest(); str.WriteAll(", #$", HexUtilities::ToHex(param2)); break;
case 0x68: str.WriteAll("RDRAM RAM:", '0' + param1, ",A");
break;
case 0x6C: str.WriteAll("RDRAM RAM:", '0' + param1, ",DPR+#$", HexUtilities::ToHex(param2));
break;
case 0x68: str.WriteAll("RDRAM RAM:", '0' + param1, ",A"); break;
case 0x6C: str.WriteAll("RDRAM RAM:", '0' + param1, ",DPR+#$", HexUtilities::ToHex(param2)); break;
case 0x70: str.Write("RDROM (a)");
break;
case 0x74: str.WriteAll("RDROM (#$", HexUtilities::ToHex((param1 << 8) | param2), ")");
break;
case 0x78: str.Write("???");
break;
case 0x70: str.Write("RDROM (a)"); break;
case 0x74: str.WriteAll("RDROM (#$", HexUtilities::ToHex((param1 << 8) | param2), ")"); break;
case 0x78: str.Write("???"); break;
case 0x7C:
if (param1 <= 1)
{
if(param1 <= 1) {
str.WriteAll("LD P", param1 ? "H" : "L", ",#$", HexUtilities::ToHex(param2));
}
else
{
} else {
str.Write("???");
}
break;
case 0x80: str.Write("ADD ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0x84: str.WriteAll("ADD ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0x88: str.Write("SUBR ");
writeSrc();
str.Write(",");
writeShiftedA();
break;
case 0x8C: str.WriteAll("SUBR #$", HexUtilities::ToHex(param2));
str.Write(",");
writeShiftedA();
break;
case 0x80: str.Write("ADD "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0x84: str.WriteAll("ADD "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0x88: str.Write("SUBR "); writeSrc(); str.Write(","); writeShiftedA(); break;
case 0x8C: str.WriteAll("SUBR #$", HexUtilities::ToHex(param2)); str.Write(","); writeShiftedA(); break;
case 0x90: str.Write("SUB ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0x94: str.WriteAll("SUB ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0x98: str.Write("SMUL A, ");
writeSrc();
break;
case 0x9C: str.WriteAll("SMUL A,#$", HexUtilities::ToHex(param2));
break;
case 0x90: str.Write("SUB "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0x94: str.WriteAll("SUB "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0x98: str.Write("SMUL A, "); writeSrc(); break;
case 0x9C: str.WriteAll("SMUL A,#$", HexUtilities::ToHex(param2)); break;
case 0xA0: str.Write("XNOR ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0xA4: str.WriteAll("XNOR ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0xA8: str.Write("XOR ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0xAC: str.WriteAll("XOR ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0xA0: str.Write("XNOR "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0xA4: str.WriteAll("XNOR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0xA8: str.Write("XOR "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0xAC: str.WriteAll("XOR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0xB0: str.Write("AND ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0xB4: str.WriteAll("AND ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0xB8: str.Write("OR ");
writeShiftedA();
str.Write(",");
writeSrc();
break;
case 0xBC: str.WriteAll("OR ");
writeShiftedA();
str.WriteAll(",#$", HexUtilities::ToHex(param2));
break;
case 0xB0: str.Write("AND "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0xB4: str.WriteAll("AND "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0xB8: str.Write("OR "); writeShiftedA(); str.Write(","); writeSrc(); break;
case 0xBC: str.WriteAll("OR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break;
case 0xC0: str.Write("SHR A,");
writeSrc();
break;
case 0xC4: str.WriteAll("SHR A,#$", HexUtilities::ToHex(param2 & 0x1F));
break;
case 0xC8: str.Write("ASR A,");
writeSrc();
break;
case 0xCC: str.WriteAll("ASR A,#$", HexUtilities::ToHex(param2 & 0x1F));
break;
case 0xC0: str.Write("SHR A,"); writeSrc(); break;
case 0xC4: str.WriteAll("SHR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break;
case 0xC8: str.Write("ASR A,"); writeSrc(); break;
case 0xCC: str.WriteAll("ASR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break;
case 0xD0: str.Write("ROR A,");
writeSrc();
break;
case 0xD4: str.WriteAll("ROR A,#$", HexUtilities::ToHex(param2 & 0x1F));
break;
case 0xD8: str.Write("SHL A,");
writeSrc();
break;
case 0xDC: str.WriteAll("SHL A,#$", HexUtilities::ToHex(param2 & 0x1F));
break;
case 0xD0: str.Write("ROR A,"); writeSrc(); break;
case 0xD4: str.WriteAll("ROR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break;
case 0xD8: str.Write("SHL A,"); writeSrc(); break;
case 0xDC: str.WriteAll("SHL A,#$", HexUtilities::ToHex(param2 & 0x1F)); break;
case 0xE0:
if (param1 <= 1)
{
str.Write("ST ");
writeSrc();
str.WriteAll(",", param1 ? "MDR" : "A");
}
else
{
if(param1 <= 1) {
str.Write("ST "); writeSrc(); str.WriteAll(",", param1 ? "MDR" : "A");
} else {
str.Write("???");
}
break;
case 0xE4: str.Write("???");
break;
case 0xE8: str.WriteAll("WRRAM A,RAM:", '0' + param1);
break;
case 0xEC: str.WriteAll("WRRAM DPR+#$", HexUtilities::ToHex(param2), ",RAM:", '0' + param1);
break;
case 0xE4: str.Write("???"); break;
case 0xE8: str.WriteAll("WRRAM A,RAM:", '0' + param1); break;
case 0xEC: str.WriteAll("WRRAM DPR+#$", HexUtilities::ToHex(param2), ",RAM:", '0' + param1); break;
case 0xF0: str.WriteAll("SWAP A,R", std::to_string(param2 & 0x0F));
break;
case 0xF4: str.Write("???");
break;
case 0xF8: str.Write("???");
break;
case 0xFC: str.Write("STOP");
break;
case 0xF0: str.WriteAll("SWAP A,R", std::to_string(param2 & 0x0F)); break;
case 0xF4: str.Write("???"); break;
case 0xF8: str.Write("???"); break;
case 0xFC: str.Write("STOP"); break;
}
out += str.ToString();

View file

@ -8,6 +8,5 @@ class EmuSettings;
class Cx4DisUtils
{
public:
static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings);
static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings);
};

View file

@ -6,7 +6,7 @@
class DebugBreakHelper
{
private:
Debugger* _debugger;
Debugger * _debugger;
bool _needResume = false;
bool _isEmulationThread = false;
@ -17,15 +17,11 @@ public:
_isEmulationThread = debugger->GetConsole()->GetEmulationThreadId() == std::this_thread::get_id();
if (!_isEmulationThread)
{
if(!_isEmulationThread) {
//Only attempt to break if this is done in a thread other than the main emulation thread
debugger->BreakRequest(false);
if (!debugger->IsExecutionStopped())
{
while (!debugger->IsExecutionStopped())
{
}
if(!debugger->IsExecutionStopped()) {
while(!debugger->IsExecutionStopped()) {}
_needResume = true;
}
}
@ -33,8 +29,7 @@ public:
~DebugBreakHelper()
{
if (!_isEmulationThread)
{
if(!_isEmulationThread) {
_debugger->BreakRequest(true);
}
}

View file

@ -27,19 +27,16 @@ void DebugHud::ClearScreen()
void DebugHud::Draw(uint32_t* argbBuffer, OverscanDimensions overscan, uint32_t lineWidth, uint32_t frameNumber)
{
auto lock = _commandLock.AcquireSafe();
for (unique_ptr<DrawCommand>& command : _commands)
{
for(unique_ptr<DrawCommand> &command : _commands) {
command->Draw(argbBuffer, overscan, lineWidth, frameNumber);
}
_commands.erase(std::remove_if(_commands.begin(), _commands.end(),
[](const unique_ptr<DrawCommand>& c) { return c->Expired(); }), _commands.end());
_commands.erase(std::remove_if(_commands.begin(), _commands.end(), [](const unique_ptr<DrawCommand>& c) { return c->Expired(); }), _commands.end());
}
void DebugHud::DrawPixel(int x, int y, int color, int frameCount, int startFrame)
{
auto lock = _commandLock.AcquireSafe();
if (_commands.size() < DebugHud::MaxCommandCount)
{
if(_commands.size() < DebugHud::MaxCommandCount) {
_commands.push_back(unique_ptr<DrawPixelCommand>(new DrawPixelCommand(x, y, color, frameCount, startFrame)));
}
}
@ -47,29 +44,23 @@ void DebugHud::DrawPixel(int x, int y, int color, int frameCount, int startFrame
void DebugHud::DrawLine(int x, int y, int x2, int y2, int color, int frameCount, int startFrame)
{
auto lock = _commandLock.AcquireSafe();
if (_commands.size() < DebugHud::MaxCommandCount)
{
_commands.push_back(
unique_ptr<DrawLineCommand>(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame)));
if(_commands.size() < DebugHud::MaxCommandCount) {
_commands.push_back(unique_ptr<DrawLineCommand>(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame)));
}
}
void DebugHud::DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame)
{
auto lock = _commandLock.AcquireSafe();
if (_commands.size() < DebugHud::MaxCommandCount)
{
_commands.push_back(
unique_ptr<DrawRectangleCommand>(
new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame)));
if(_commands.size() < DebugHud::MaxCommandCount) {
_commands.push_back(unique_ptr<DrawRectangleCommand>(new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame)));
}
}
void DebugHud::DrawScreenBuffer(uint32_t* screenBuffer, int startFrame)
{
auto lock = _commandLock.AcquireSafe();
if (_commands.size() < DebugHud::MaxCommandCount)
{
if(_commands.size() < DebugHud::MaxCommandCount) {
_commands.push_back(unique_ptr<DrawScreenBufferCommand>(new DrawScreenBufferCommand(screenBuffer, startFrame)));
}
}
@ -77,9 +68,7 @@ void DebugHud::DrawScreenBuffer(uint32_t* screenBuffer, int startFrame)
void DebugHud::DrawString(int x, int y, string text, int color, int backColor, int frameCount, int startFrame)
{
auto lock = _commandLock.AcquireSafe();
if (_commands.size() < DebugHud::MaxCommandCount)
{
_commands.push_back(
unique_ptr<DrawStringCommand>(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame)));
if(_commands.size() < DebugHud::MaxCommandCount) {
_commands.push_back(unique_ptr<DrawStringCommand>(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame)));
}
}

View file

@ -6,7 +6,7 @@
#include "DebugHud.h"
#include "IAudioDevice.h"
void DebugStats::DisplayStats(Console* console, double lastFrameTime)
void DebugStats::DisplayStats(Console *console, double lastFrameTime)
{
AudioStatistics stats = console->GetSoundMixer()->GetStatistics();
AudioConfig audioCfg = console->GetSettings()->GetAudioConfig();
@ -23,29 +23,21 @@ void DebugStats::DisplayStats(Console* console, double lastFrameTime)
hud->DrawString(10, 10, "Audio Stats", 0xFFFFFF, 0xFF000000, 1, startFrame);
hud->DrawString(10, 21, "Latency: ", 0xFFFFFF, 0xFF000000, 1, startFrame);
int color = (stats.AverageLatency > 0 && std::abs(stats.AverageLatency - audioCfg.AudioLatency) > 3)
? 0xFF0000
: 0xFFFFFF;
int color = (stats.AverageLatency > 0 && std::abs(stats.AverageLatency - audioCfg.AudioLatency) > 3) ? 0xFF0000 : 0xFFFFFF;
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << stats.AverageLatency << " ms";
hud->DrawString(54, 21, ss.str(), color, 0xFF000000, 1, startFrame);
hud->DrawString(10, 30, "Underruns: " + std::to_string(stats.BufferUnderrunEventCount), 0xFFFFFF, 0xFF000000, 1,
startFrame);
hud->DrawString(10, 39, "Buffer Size: " + std::to_string(stats.BufferSize / 1024) + "kb", 0xFFFFFF, 0xFF000000, 1,
startFrame);
hud->DrawString(
10, 48,
"Rate: " + std::to_string((uint32_t)(audioCfg.SampleRate * console->GetSoundMixer()->GetRateAdjustment())) + "Hz",
0xFFFFFF, 0xFF000000, 1, startFrame);
hud->DrawString(10, 30, "Underruns: " + std::to_string(stats.BufferUnderrunEventCount), 0xFFFFFF, 0xFF000000, 1, startFrame);
hud->DrawString(10, 39, "Buffer Size: " + std::to_string(stats.BufferSize / 1024) + "kb", 0xFFFFFF, 0xFF000000, 1, startFrame);
hud->DrawString(10, 48, "Rate: " + std::to_string((uint32_t)(audioCfg.SampleRate * console->GetSoundMixer()->GetRateAdjustment())) + "Hz", 0xFFFFFF, 0xFF000000, 1, startFrame);
hud->DrawRectangle(132, 8, 115, 49, 0x40000000, true, 1, startFrame);
hud->DrawRectangle(132, 8, 115, 49, 0xFFFFFF, false, 1, startFrame);
hud->DrawString(134, 10, "Video Stats", 0xFFFFFF, 0xFF000000, 1, startFrame);
double totalDuration = 0;
for (int i = 0; i < 60; i++)
{
for(int i = 0; i < 60; i++) {
totalDuration += _frameDurations[i];
}
@ -57,13 +49,10 @@ void DebugStats::DisplayStats(Console* console, double lastFrameTime)
ss << "Last Frame: " << std::fixed << std::setprecision(2) << lastFrameTime << " ms";
hud->DrawString(134, 30, ss.str(), 0xFFFFFF, 0xFF000000, 1, startFrame);
if (console->GetFrameCount() > 60)
{
if(console->GetFrameCount() > 60) {
_lastFrameMin = std::min(lastFrameTime, _lastFrameMin);
_lastFrameMax = std::max(lastFrameTime, _lastFrameMax);
}
else
{
} else {
_lastFrameMin = 9999;
_lastFrameMax = 0;
}

View file

@ -12,5 +12,5 @@ private:
double _lastFrameMax = 0;
public:
void DisplayStats(Console* console, double lastFrameTime);
void DisplayStats(Console *console, double lastFrameTime);
};

View file

@ -7,8 +7,7 @@ class DebugUtilities
public:
static SnesMemoryType GetCpuMemoryType(CpuType type)
{
switch (type)
{
switch(type) {
case CpuType::Cpu: return SnesMemoryType::CpuMemory;
case CpuType::Spc: return SnesMemoryType::SpcMemory;
case CpuType::NecDsp: return SnesMemoryType::NecDspMemory;
@ -23,8 +22,7 @@ public:
static CpuType ToCpuType(SnesMemoryType type)
{
switch (type)
{
switch(type) {
case SnesMemoryType::SpcMemory:
case SnesMemoryType::SpcRam:
case SnesMemoryType::SpcRom:
@ -71,8 +69,7 @@ public:
static bool IsPpuMemory(SnesMemoryType memType)
{
switch (memType)
{
switch(memType) {
case SnesMemoryType::VideoRam:
case SnesMemoryType::SpriteRam:
case SnesMemoryType::CGRam:
@ -87,8 +84,7 @@ public:
static bool IsRomMemory(SnesMemoryType memType)
{
switch (memType)
{
switch(memType) {
case SnesMemoryType::PrgRom:
case SnesMemoryType::GbPrgRom:
case SnesMemoryType::GbBootRom:

File diff suppressed because it is too large Load diff

View file

@ -92,10 +92,10 @@ public:
~Debugger();
void Release();
template <CpuType type>
template<CpuType type>
void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType);
template <CpuType type>
template<CpuType type>
void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType);
void ProcessWorkRamRead(uint32_t addr, uint8_t value);
@ -104,15 +104,15 @@ public:
void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
template <CpuType cpuType>
template<CpuType cpuType>
void ProcessPpuCycle();
template <CpuType type>
template<CpuType type>
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);
int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType& resultType, bool useCache);
int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache);
void Run();
void Step(CpuType cpuType, int32_t stepCount, StepType type);
@ -124,8 +124,7 @@ public:
void BreakImmediately(BreakSource source);
void ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo& operation,
AddressInfo& addressInfo, BreakSource source = BreakSource::Unspecified);
void ProcessBreakConditions(bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified);
void SleepUntilResume(BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1);
void GetState(DebugState& state, bool partialPpuState);
@ -144,7 +143,7 @@ public:
AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType);
void GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData);
void SetCdlData(CpuType cpuType, uint8_t* cdlData, uint32_t length);
void SetCdlData(CpuType cpuType, uint8_t * cdlData, uint32_t length);
void MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags);
void RefreshCodeCache();

View file

@ -20,15 +20,14 @@ void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturation
double hue = hueShift * PI;
double sat = saturationShift + 1;
double baseValues[6] = {0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f};
double baseValues[6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
double s = sin(hue) * sat;
double c = cos(hue) * sat;
double* output = _yiqToRgbMatrix;
double* input = baseValues;
for (int n = 0; n < 3; n++)
{
double *output = _yiqToRgbMatrix;
double *input = baseValues;
for(int n = 0; n < 3; n++) {
double i = *input++;
double q = *input++;
*output++ = i * c - q * s;
@ -43,29 +42,24 @@ void DefaultVideoFilter::InitLookupTable()
InitConversionMatrix(config.Hue, config.Saturation);
double y, i, q;
for (int rgb555 = 0; rgb555 < 0x8000; rgb555++)
{
for(int rgb555 = 0; rgb555 < 0x8000; rgb555++) {
uint8_t r = rgb555 & 0x1F;
uint8_t g = (rgb555 >> 5) & 0x1F;
uint8_t b = (rgb555 >> 10) & 0x1F;
if (_gbcAdjustColors)
{
if(_gbcAdjustColors) {
uint8_t r2 = std::min(240, (r * 26 + g * 4 + b * 2) >> 2);
uint8_t g2 = std::min(240, (g * 24 + b * 8) >> 2);
uint8_t b2 = std::min(240, (r * 6 + g * 4 + b * 22) >> 2);
r = r2;
g = g2;
b = b2;
}
else
{
} else {
r = To8Bit(r);
g = To8Bit(g);
b = To8Bit(b);
}
if (config.Hue != 0 || config.Saturation != 0 || config.Brightness != 0 || config.Contrast != 0)
{
if(config.Hue != 0 || config.Saturation != 0 || config.Brightness != 0 || config.Contrast != 0) {
double redChannel = r / 255.0;
double greenChannel = g / 255.0;
double blueChannel = b / 255.0;
@ -80,9 +74,7 @@ void DefaultVideoFilter::InitLookupTable()
int g = std::min(255, (int)(greenChannel * 255));
int b = std::min(255, (int)(blueChannel * 255));
_calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else
{
} else {
_calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
@ -97,14 +89,11 @@ void DefaultVideoFilter::OnBeforeApplyFilter()
ConsoleType consoleType = _console->GetConsoleType();
bool adjustColors = gbConfig.GbcAdjustColors && consoleType == ConsoleType::GameboyColor;
if (_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config
.Contrast || _videoConfig.Brightness != config.Brightness || _gbcAdjustColors != adjustColors)
{
if(_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config.Contrast || _videoConfig.Brightness != config.Brightness || _gbcAdjustColors != adjustColors) {
_gbcAdjustColors = adjustColors;
InitLookupTable();
}
_gbBlendFrames = gbConfig.BlendFrames && (consoleType == ConsoleType::Gameboy || consoleType ==
ConsoleType::GameboyColor);
_gbBlendFrames = gbConfig.BlendFrames && (consoleType == ConsoleType::Gameboy || consoleType == ConsoleType::GameboyColor);
_videoConfig = config;
}
@ -122,9 +111,9 @@ uint32_t DefaultVideoFilter::ToArgb(uint16_t rgb555)
return 0xFF000000 | (r << 16) | (g << 8) | b;
}
void DefaultVideoFilter::ApplyFilter(uint16_t* ppuOutputBuffer)
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
uint32_t* out = GetOutputBuffer();
uint32_t *out = GetOutputBuffer();
FrameInfo frameInfo = GetFrameInfo();
OverscanDimensions overscan = GetOverscan();
@ -134,70 +123,51 @@ void DefaultVideoFilter::ApplyFilter(uint16_t* ppuOutputBuffer)
uint32_t yOffset = overscan.Top * overscanMultiplier * width;
uint8_t scanlineIntensity = (uint8_t)((1.0 - _console->GetSettings()->GetVideoConfig().ScanlineIntensity) * 255);
if (scanlineIntensity < 255)
{
for (uint32_t i = 0; i < frameInfo.Height; i++)
{
if (i & 0x01)
{
for (uint32_t j = 0; j < frameInfo.Width; j++)
{
*out = ApplyScanlineEffect(GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset),
scanlineIntensity);
if(scanlineIntensity < 255) {
for(uint32_t i = 0; i < frameInfo.Height; i++) {
if(i & 0x01) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = ApplyScanlineEffect(GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset), scanlineIntensity);
out++;
}
}
else
{
for (uint32_t j = 0; j < frameInfo.Width; j++)
{
} else {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset);
out++;
}
}
}
}
else
{
for (uint32_t i = 0; i < frameInfo.Height; i++)
{
for (uint32_t j = 0; j < frameInfo.Width; j++)
{
out[i * frameInfo.Width + j] = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset);
} else {
for(uint32_t i = 0; i < frameInfo.Height; i++) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
out[i*frameInfo.Width+j] = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset);
}
}
}
if (_baseFrameInfo.Width == 512 && _videoConfig.BlendHighResolutionModes)
{
if(_baseFrameInfo.Width == 512 && _videoConfig.BlendHighResolutionModes) {
//Very basic blend effect for high resolution modes
for (uint32_t i = 0; i < frameInfo.Height; i += 2)
{
for (uint32_t j = 0; j < frameInfo.Width; j += 2)
{
uint32_t& pixel1 = out[i * frameInfo.Width + j];
uint32_t& pixel2 = out[i * frameInfo.Width + j + 1];
uint32_t& pixel3 = out[(i + 1) * frameInfo.Width + j];
uint32_t& pixel4 = out[(i + 1) * frameInfo.Width + j + 1];
for(uint32_t i = 0; i < frameInfo.Height; i+=2) {
for(uint32_t j = 0; j < frameInfo.Width; j+=2) {
uint32_t &pixel1 = out[i*frameInfo.Width + j];
uint32_t &pixel2 = out[i*frameInfo.Width + j + 1];
uint32_t &pixel3 = out[(i+1)*frameInfo.Width + j];
uint32_t &pixel4 = out[(i+1)*frameInfo.Width + j + 1];
pixel1 = pixel2 = pixel3 = pixel4 = BlendPixels(BlendPixels(BlendPixels(pixel1, pixel2), pixel3), pixel4);
}
}
}
if (_gbBlendFrames)
{
if(_gbBlendFrames) {
std::copy(ppuOutputBuffer, ppuOutputBuffer + 256 * 240, _prevFrame);
}
}
uint32_t DefaultVideoFilter::GetPixel(uint16_t* ppuFrame, uint32_t offset)
{
if (_gbBlendFrames)
{
if(_gbBlendFrames) {
return BlendPixels(_calculatedPalette[_prevFrame[offset]], _calculatedPalette[ppuFrame[offset]]);
}
else
{
} else {
return _calculatedPalette[ppuFrame[offset]];
}
}
@ -207,14 +177,14 @@ uint32_t DefaultVideoFilter::BlendPixels(uint32_t a, uint32_t b)
return ((((a) ^ (b)) & 0xfffefefeL) >> 1) + ((a) & (b));
}
void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double& y, double& i, double& q)
void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double &y, double &i, double &q)
{
y = r * 0.299f + g * 0.587f + b * 0.114f;
i = r * 0.596f - g * 0.275f - b * 0.321f;
q = r * 0.212f - g * 0.523f + b * 0.311f;
}
void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double& r, double& g, double& b)
void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double &r, double &g, double &b)
{
r = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[0] * i + _yiqToRgbMatrix[1] * q)));
g = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[2] * i + _yiqToRgbMatrix[3] * q)));

View file

@ -18,8 +18,8 @@ private:
void InitConversionMatrix(double hueShift, double saturationShift);
void InitLookupTable();
void RgbToYiq(double r, double g, double b, double& y, double& i, double& q);
void YiqToRgb(double y, double i, double q, double& r, double& g, double& b);
void RgbToYiq(double r, double g, double b, double &y, double &i, double &q);
void YiqToRgb(double y, double i, double q, double &r, double &g, double &b);
__forceinline static uint8_t To8Bit(uint8_t color);
__forceinline static uint32_t BlendPixels(uint32_t a, uint32_t b);
__forceinline uint32_t GetPixel(uint16_t* ppuFrame, uint32_t offset);
@ -29,7 +29,7 @@ protected:
public:
DefaultVideoFilter(shared_ptr<Console> console);
void ApplyFilter(uint16_t* ppuOutputBuffer);
void ApplyFilter(uint16_t *ppuOutputBuffer);
static uint32_t ToArgb(uint16_t rgb555);
};

View file

@ -46,21 +46,18 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
_memoryDumper = _debugger->GetMemoryDumper().get();
_memoryManager = console->GetMemoryManager().get();
for (int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++)
{
for(int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) {
_disassemblyResult[i] = vector<DisassemblyResult>();
_needDisassemble[i] = true;
}
for (int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++)
{
for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) {
InitSource((SnesMemoryType)i);
}
if (_necDsp)
{
if(_necDsp) {
//Build cache for the entire DSP chip (since it only contains instructions)
AddressInfo dspStart = {0, SnesMemoryType::DspProgramRom};
AddressInfo dspStart = { 0, SnesMemoryType::DspProgramRom };
BuildCache(dspStart, 0, CpuType::NecDsp);
}
}
@ -70,49 +67,42 @@ void Disassembler::InitSource(SnesMemoryType type)
uint8_t* src = _memoryDumper->GetMemoryBuffer(type);
uint32_t size = _memoryDumper->GetMemorySize(type);
_disassemblyCache[(int)type] = vector<DisassemblyInfo>(size);
_sources[(int)type] = {src, &_disassemblyCache[(int)type], size};
_sources[(int)type] = { src, &_disassemblyCache[(int)type], size };
}
DisassemblerSource& Disassembler::GetSource(SnesMemoryType type)
{
if (_sources[(int)type].Data == nullptr)
{
if(_sources[(int)type].Data == nullptr) {
throw std::runtime_error("Disassembler::GetSource() invalid memory type");
}
return _sources[(int)type];
}
uint32_t Disassembler::BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuType type)
uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type)
{
DisassemblerSource& src = GetSource(addrInfo.Type);
bool needDisassemble = false;
int returnSize = 0;
int32_t address = addrInfo.Address;
while (address >= 0 && address < (int32_t)src.Cache->size())
{
DisassemblyInfo& disInfo = (*src.Cache)[address];
if (!disInfo.IsInitialized() || !disInfo.IsValid(cpuFlags))
{
disInfo.Initialize(src.Data + address, cpuFlags, type);
for (int i = 1; i < disInfo.GetOpSize(); i++)
{
while(address >= 0 && address < (int32_t)src.Cache->size()) {
DisassemblyInfo &disInfo = (*src.Cache)[address];
if(!disInfo.IsInitialized() || !disInfo.IsValid(cpuFlags)) {
disInfo.Initialize(src.Data+address, cpuFlags, type);
for(int i = 1; i < disInfo.GetOpSize(); i++) {
//Clear any instructions that start in the middle of this one
//(can happen when resizing an instruction after X/M updates)
(*src.Cache)[address + i] = DisassemblyInfo();
}
needDisassemble = true;
returnSize += disInfo.GetOpSize();
}
else
{
} else {
returnSize += disInfo.GetOpSize();
break;
}
if (disInfo.IsUnconditionalJump())
{
if(disInfo.IsUnconditionalJump()) {
//Can't assume what follows is code, stop disassembling
break;
}
@ -121,8 +111,7 @@ uint32_t Disassembler::BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuTy
address += disInfo.GetOpSize();
}
if (needDisassemble)
{
if(needDisassemble) {
SetDisassembleFlag(type);
}
@ -131,15 +120,12 @@ uint32_t Disassembler::BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuTy
void Disassembler::SetDisassembleFlag(CpuType type)
{
if (type == CpuType::Cpu || type == CpuType::Sa1 || type == CpuType::Gsu || type == CpuType::Cx4)
{
if(type == CpuType::Cpu || type == CpuType::Sa1 || type == CpuType::Gsu || type == CpuType::Cx4) {
_needDisassemble[(int)CpuType::Cpu] = true;
_needDisassemble[(int)CpuType::Sa1] = true;
_needDisassemble[(int)CpuType::Gsu] = true;
_needDisassemble[(int)CpuType::Cx4] = true;
}
else
{
} else {
_needDisassemble[(int)type] = true;
}
}
@ -160,14 +146,10 @@ void Disassembler::InvalidateCache(AddressInfo addrInfo, CpuType type)
DisassemblerSource src = GetSource(addrInfo.Type);
bool needDisassemble = false;
if (addrInfo.Address >= 0)
{
for (int i = 0; i < 4; i++)
{
if (addrInfo.Address >= i)
{
if ((*src.Cache)[addrInfo.Address - i].IsInitialized())
{
if(addrInfo.Address >= 0) {
for(int i = 0; i < 4; i++) {
if(addrInfo.Address >= i) {
if((*src.Cache)[addrInfo.Address - i].IsInitialized()) {
(*src.Cache)[addrInfo.Address - i].Reset();
needDisassemble = true;
}
@ -175,16 +157,14 @@ void Disassembler::InvalidateCache(AddressInfo addrInfo, CpuType type)
}
}
if (needDisassemble)
{
if(needDisassemble) {
SetDisassembleFlag(type);
}
}
void Disassembler::Disassemble(CpuType cpuType)
{
if (!_needDisassemble[(int)cpuType])
{
if(!_needDisassemble[(int)cpuType]) {
return;
}
@ -192,33 +172,29 @@ void Disassembler::Disassemble(CpuType cpuType)
auto lock = _disassemblyLock.AcquireSafe();
MemoryMappings* mappings = nullptr;
MemoryMappings *mappings = nullptr;
int32_t maxAddr = 0xFFFFFF;
switch (cpuType)
{
switch(cpuType) {
case CpuType::Cpu:
mappings = _memoryManager->GetMemoryMappings();
break;
case CpuType::Sa1:
if (!_sa1)
{
if(!_sa1) {
return;
}
mappings = _sa1->GetMemoryMappings();
break;
case CpuType::Gsu:
if (!_gsu)
{
if(!_gsu) {
return;
}
mappings = _gsu->GetMemoryMappings();
break;
case CpuType::NecDsp:
if (!_console->GetCartridge()->GetDsp())
{
if(!_console->GetCartridge()->GetDsp()) {
return;
}
mappings = nullptr;
@ -231,8 +207,7 @@ void Disassembler::Disassemble(CpuType cpuType)
break;
case CpuType::Gameboy:
if (!_gameboy)
{
if(!_gameboy) {
return;
}
mappings = nullptr;
@ -240,8 +215,7 @@ void Disassembler::Disassemble(CpuType cpuType)
break;
case CpuType::Cx4:
if (!_console->GetCartridge()->GetCx4())
{
if(!_console->GetCartridge()->GetCx4()) {
return;
}
mappings = _console->GetCartridge()->GetCx4()->GetMemoryMappings();
@ -250,7 +224,7 @@ void Disassembler::Disassemble(CpuType cpuType)
default: throw std::runtime_error("Disassemble(): Invalid cpu type");
}
vector<DisassemblyResult>& results = _disassemblyResult[(int)cpuType];
vector<DisassemblyResult> &results = _disassemblyResult[(int)cpuType];
results.clear();
bool disUnident = _settings->CheckDebuggerFlag(DebuggerFlags::DisassembleUnidentifiedData);
@ -264,23 +238,16 @@ void Disassembler::Disassemble(CpuType cpuType)
AddressInfo addrInfo = {};
AddressInfo prevAddrInfo = {};
int byteCounter = 0;
for (int32_t i = 0; i <= maxAddr; i++)
{
for(int32_t i = 0; i <= maxAddr; i++) {
prevAddrInfo = addrInfo;
switch (cpuType)
{
case CpuType::Spc: addrInfo = _spc->GetAbsoluteAddress(i);
break;
case CpuType::NecDsp: addrInfo = {i, SnesMemoryType::DspProgramRom};
break;
case CpuType::Gameboy: addrInfo = _gameboy->GetAbsoluteAddress(i);
break;
default: addrInfo = mappings->GetAbsoluteAddress(i);
break;
switch(cpuType) {
case CpuType::Spc: addrInfo = _spc->GetAbsoluteAddress(i); break;
case CpuType::NecDsp: addrInfo = { i, SnesMemoryType::DspProgramRom }; break;
case CpuType::Gameboy: addrInfo = _gameboy->GetAbsoluteAddress(i); break;
default: addrInfo = mappings->GetAbsoluteAddress(i); break;
}
if (addrInfo.Address < 0)
{
if(addrInfo.Address < 0) {
continue;
}
@ -294,43 +261,31 @@ void Disassembler::Disassemble(CpuType cpuType)
bool isCode = addrInfo.Type == SnesMemoryType::PrgRom ? _cdl->IsCode(addrInfo.Address) : false;
bool isData = addrInfo.Type == SnesMemoryType::PrgRom ? _cdl->IsData(addrInfo.Address) : false;
if (disassemblyInfo.IsInitialized())
{
if(disassemblyInfo.IsInitialized()) {
opSize = disassemblyInfo.GetOpSize();
}
else if ((isData && disData) || (!isData && !isCode && disUnident))
{
} else if((isData && disData) || (!isData && !isCode && disUnident)) {
opSize = DisassemblyInfo::GetOpSize(opCode, 0, cpuType);
}
if (opSize > 0)
{
if (inUnknownBlock || inVerifiedBlock)
{
int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (
((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0);
if(opSize > 0) {
if(inUnknownBlock || inVerifiedBlock) {
int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0);
results.push_back(DisassemblyResult(prevAddrInfo, i - 1, flags));
inUnknownBlock = false;
inVerifiedBlock = false;
}
byteCounter = 0;
if (addrInfo.Type == SnesMemoryType::PrgRom && _cdl->IsSubEntryPoint(addrInfo.Address))
{
results.push_back(DisassemblyResult(addrInfo, i,
LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode));
if(addrInfo.Type == SnesMemoryType::PrgRom && _cdl->IsSubEntryPoint(addrInfo.Address)) {
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode));
}
if (_labelManager->GetLabelAndComment(addrInfo, labelInfo))
{
if(_labelManager->GetLabelAndComment(addrInfo, labelInfo)) {
bool hasMultipleComment = labelInfo.Comment.find_first_of('\n') != string::npos;
if (hasMultipleComment)
{
if(hasMultipleComment) {
int16_t lineCount = 0;
for (char c : labelInfo.Comment)
{
if (c == '\n')
{
for(char c : labelInfo.Comment) {
if(c == '\n') {
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment, lineCount));
lineCount++;
}
@ -338,62 +293,42 @@ void Disassembler::Disassemble(CpuType cpuType)
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment, lineCount));
}
if (labelInfo.Label.size())
{
if(labelInfo.Label.size()) {
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Label));
}
if (!hasMultipleComment && labelInfo.Comment.size())
{
if(!hasMultipleComment && labelInfo.Comment.size()) {
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment));
}
else
{
} else {
results.push_back(DisassemblyResult(addrInfo, i));
}
}
else
{
} else {
results.push_back(DisassemblyResult(addrInfo, i));
}
//Move to the end of the instruction (but realign disassembly if another valid instruction is found)
//This can sometimes happen if the 2nd byte of BRK/COP is reused as the first byte of the next instruction
//Also required when disassembling unvalidated data as code (to realign once we find verified code)
for (int j = 1, max = (int)(*src.Cache).size(); j < opSize && addrInfo.Address + j < max; j++)
{
if ((*src.Cache)[addrInfo.Address + j].IsInitialized())
{
for(int j = 1, max = (int)(*src.Cache).size(); j < opSize && addrInfo.Address + j < max; j++) {
if((*src.Cache)[addrInfo.Address + j].IsInitialized()) {
break;
}
i++;
}
if (DisassemblyInfo::IsReturnInstruction(opCode, cpuType))
{
if(DisassemblyInfo::IsReturnInstruction(opCode, cpuType)) {
//End of function
results.push_back(DisassemblyResult(-1, LineFlags::VerifiedCode | LineFlags::BlockEnd));
}
}
else
{
if (showData || showUnident)
{
if ((isData && inUnknownBlock) || (!isData && inVerifiedBlock))
{
if (isData && inUnknownBlock)
{
} else {
if(showData || showUnident) {
if((isData && inUnknownBlock) || (!isData && inVerifiedBlock)) {
if(isData && inUnknownBlock) {
//In an unknown block and the next byte is data, end the block
results.push_back(DisassemblyResult(prevAddrInfo, i - 1,
LineFlags::BlockEnd | (showUnident ? LineFlags::ShowAsData : 0)));
}
else if (!isData && inVerifiedBlock)
{
results.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd | (showUnident ? LineFlags::ShowAsData : 0)));
} else if(!isData && inVerifiedBlock) {
//In a verified data block and the next byte is unknown, end the block
results.push_back(DisassemblyResult(prevAddrInfo, i - 1,
LineFlags::BlockEnd | LineFlags::VerifiedData | (showData
? LineFlags::ShowAsData
: 0)));
results.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd | LineFlags::VerifiedData | (showData ? LineFlags::ShowAsData : 0)));
}
inUnknownBlock = false;
inVerifiedBlock = false;
@ -401,45 +336,29 @@ void Disassembler::Disassemble(CpuType cpuType)
}
}
if (byteCounter > 0)
{
if(byteCounter > 0) {
//If showing as hex data, add a new data line every 8 bytes
byteCounter--;
if (byteCounter == 0)
{
results.push_back(DisassemblyResult(addrInfo, i,
LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0)));
if(byteCounter == 0) {
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0)));
byteCounter = 8;
}
}
else if (!inUnknownBlock && !inVerifiedBlock)
{
} else if(!inUnknownBlock && !inVerifiedBlock) {
//If not in a block, start a new block based on the current byte's type (data vs unidentified)
bool showAsData = (isData && showData) || ((!isData && !isCode) && showUnident);
if (isData)
{
if(isData) {
inVerifiedBlock = true;
results.push_back(DisassemblyResult(addrInfo, i,
LineFlags::BlockStart | LineFlags::VerifiedData | (showAsData
? LineFlags::ShowAsData
: 0)));
}
else
{
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart | LineFlags::VerifiedData | (showAsData ? LineFlags::ShowAsData : 0)));
} else {
inUnknownBlock = true;
results.push_back(DisassemblyResult(addrInfo, i,
LineFlags::BlockStart | (showAsData ? LineFlags::ShowAsData : 0)));
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart | (showAsData ? LineFlags::ShowAsData : 0)));
}
if (showAsData)
{
if(showAsData) {
//If showing data as hex, add the first row of the block
results.push_back(DisassemblyResult(addrInfo, i,
LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0)));
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0)));
byteCounter = 8;
}
else
{
} else {
//If not showing the data at all, display 1 empty line
results.push_back(DisassemblyResult(-1, LineFlags::None | (isData ? LineFlags::VerifiedData : 0)));
}
@ -447,19 +366,16 @@ void Disassembler::Disassemble(CpuType cpuType)
}
}
if (inUnknownBlock || inVerifiedBlock)
{
int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (
((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0);
if(inUnknownBlock || inVerifiedBlock) {
int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0);
results.push_back(DisassemblyResult(addrInfo, maxAddr, flags));
}
}
DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo& info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type)
DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo &info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type)
{
DisassemblyInfo disassemblyInfo = (*GetSource(info.Type).Cache)[info.Address];
if (!disassemblyInfo.IsInitialized())
{
if(!disassemblyInfo.IsInitialized()) {
disassemblyInfo.Initialize(cpuAddress, cpuFlags, type, _memoryDumper);
}
return disassemblyInfo;
@ -484,20 +400,14 @@ uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress)
auto lock = _disassemblyLock.AcquireSafe();
vector<DisassemblyResult>& source = _disassemblyResult[(int)type];
uint32_t lastAddress = 0;
for (size_t i = 1; i < source.size(); i++)
{
if (source[i].CpuAddress < 0 || (source[i].Flags & LineFlags::SubStart) | (source[i].Flags & LineFlags::Label) ||
((source[i].Flags & LineFlags::Comment) && source[i].CommentLine >= 0))
{
for(size_t i = 1; i < source.size(); i++) {
if(source[i].CpuAddress < 0 || (source[i].Flags & LineFlags::SubStart) | (source[i].Flags & LineFlags::Label) || ((source[i].Flags & LineFlags::Comment) && source[i].CommentLine >= 0)) {
continue;
}
if (cpuAddress == (uint32_t)source[i].CpuAddress)
{
if(cpuAddress == (uint32_t)source[i].CpuAddress) {
return (uint32_t)i;
}
else if (cpuAddress >= lastAddress && cpuAddress < (uint32_t)source[i].CpuAddress)
{
} else if(cpuAddress >= lastAddress && cpuAddress < (uint32_t)source[i].CpuAddress) {
return (uint32_t)i - 1;
}
@ -506,68 +416,53 @@ uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress)
return 0;
}
bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& data)
bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data)
{
auto lock = _disassemblyLock.AcquireSafe();
auto lock =_disassemblyLock.AcquireSafe();
vector<DisassemblyResult>& source = _disassemblyResult[(int)type];
SnesMemoryType memType = DebugUtilities::GetCpuMemoryType(type);
int32_t maxAddr = type == CpuType::Spc ? 0xFFFF : 0xFFFFFF;
if (lineIndex < source.size())
{
if(lineIndex < source.size()) {
DisassemblyResult result = source[lineIndex];
data.Address = -1;
data.AbsoluteAddress = -1;
data.EffectiveAddress = -1;
data.Flags = result.Flags;
switch (result.Address.Type)
{
switch(result.Address.Type) {
default: break;
case SnesMemoryType::GbPrgRom:
case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom;
break;
case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break;
case SnesMemoryType::GbWorkRam:
case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam;
break;
case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; break;
case SnesMemoryType::GbCartRam:
case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam;
break;
case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break;
}
bool isBlockStartEnd = (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) != 0;
if (!isBlockStartEnd && result.Address.Address >= 0)
{
if ((data.Flags & LineFlags::ShowAsData))
{
if(!isBlockStartEnd && result.Address.Address >= 0) {
if((data.Flags & LineFlags::ShowAsData)) {
FastString str(".db", 3);
int nextAddr = lineIndex < source.size() - 2 ? (source[lineIndex + 1].CpuAddress + 1) : (maxAddr + 1);
for (int i = 0; i < 8 && result.CpuAddress + i < nextAddr; i++)
{
int nextAddr = lineIndex < source.size() - 2 ? (source[lineIndex+1].CpuAddress + 1) : (maxAddr + 1);
for(int i = 0; i < 8 && result.CpuAddress+i < nextAddr; i++) {
str.Write(" $", 2);
str.Write(HexUtilities::ToHexChar(_memoryDumper->GetMemoryValue(memType, result.CpuAddress + i)), 2);
}
data.Address = result.CpuAddress;
data.AbsoluteAddress = result.Address.Address;
memcpy(data.Text, str.ToString(), str.GetSize());
}
else if ((data.Flags & LineFlags::Comment) && result.CommentLine >= 0)
{
string comment = ";" + StringUtilities::Split(_labelManager->GetComment(result.Address), '\n')[result.
CommentLine];
} else if((data.Flags & LineFlags::Comment) && result.CommentLine >= 0) {
string comment = ";" + StringUtilities::Split(_labelManager->GetComment(result.Address), '\n')[result.CommentLine];
data.Flags |= LineFlags::VerifiedCode;
memcpy(data.Comment, comment.c_str(), std::min<int>((int)comment.size(), 1000));
}
else if (data.Flags & LineFlags::Label)
{
} else if(data.Flags & LineFlags::Label) {
string label = _labelManager->GetLabel(result.Address) + ":";
data.Flags |= LineFlags::VerifiedCode;
memcpy(data.Text, label.c_str(), std::min<int>((int)label.size(), 1000));
}
else
{
} else {
DisassemblerSource src = GetSource(result.Address.Type);
DisassemblyInfo disInfo = (*src.Cache)[result.Address.Address];
CpuType lineCpuType = disInfo.IsInitialized() ? disInfo.GetCpuType() : type;
@ -575,89 +470,65 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& d
data.Address = result.CpuAddress;
data.AbsoluteAddress = result.Address.Address;
switch (lineCpuType)
{
switch(lineCpuType) {
case CpuType::Cpu:
case CpuType::Sa1:
{
case CpuType::Sa1: {
CpuState state = type == CpuType::Sa1 ? _sa1->GetCpuState() : _cpu->GetState();
state.PC = (uint16_t)result.CpuAddress;
state.K = (result.CpuAddress >> 16);
if (!disInfo.IsInitialized())
{
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, state.PS, lineCpuType);
}
else
{
data.Flags |= (result.Address.Type != SnesMemoryType::PrgRom || _cdl->IsCode(data.AbsoluteAddress))
? LineFlags::VerifiedCode
: LineFlags::UnexecutedCode;
} else {
data.Flags |= (result.Address.Type != SnesMemoryType::PrgRom || _cdl->IsCode(data.AbsoluteAddress)) ? LineFlags::VerifiedCode : LineFlags::UnexecutedCode;
}
data.OpSize = disInfo.GetOpSize();
data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType);
if (data.EffectiveAddress >= 0)
{
if(data.EffectiveAddress >= 0) {
data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize);
}
else
{
} else {
data.ValueSize = 0;
}
break;
}
case CpuType::Spc:
{
case CpuType::Spc: {
SpcState state = _spc->GetState();
state.PC = (uint16_t)result.CpuAddress;
if (!disInfo.IsInitialized())
{
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Spc);
}
else
{
} else {
data.Flags |= LineFlags::VerifiedCode;
}
data.OpSize = disInfo.GetOpSize();
data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType);
if (data.EffectiveAddress >= 0)
{
if(data.EffectiveAddress >= 0) {
data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize);
data.ValueSize = 1;
}
else
{
} else {
data.ValueSize = 0;
}
break;
}
case CpuType::Gsu:
{
case CpuType::Gsu: {
GsuState state = _gsu->GetState();
if (!disInfo.IsInitialized())
{
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Gsu);
}
else
{
} else {
data.Flags |= LineFlags::VerifiedCode;
}
data.OpSize = disInfo.GetOpSize();
data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType);
if (data.EffectiveAddress >= 0)
{
if(data.EffectiveAddress >= 0) {
data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize);
data.ValueSize = 2;
}
else
{
} else {
data.ValueSize = 0;
}
break;
@ -665,12 +536,9 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& d
case CpuType::NecDsp:
case CpuType::Cx4:
if (!disInfo.IsInitialized())
{
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, type);
}
else
{
} else {
data.Flags |= LineFlags::VerifiedCode;
}
@ -679,15 +547,11 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& d
data.ValueSize = 0;
break;
case CpuType::Gameboy:
{
case CpuType::Gameboy: {
GbCpuState state = _gameboy->GetCpu()->GetState();
if (!disInfo.IsInitialized())
{
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Gameboy);
}
else
{
} else {
data.Flags |= LineFlags::VerifiedCode;
}
@ -704,38 +568,27 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& d
disInfo.GetByteCode(data.ByteCode);
if (data.Flags & LineFlags::Comment)
{
if(data.Flags & LineFlags::Comment) {
string comment = ";" + _labelManager->GetComment(result.Address);
memcpy(data.Comment, comment.c_str(), std::min<int>((int)comment.size(), 1000));
}
else
{
} else {
data.Comment[0] = 0;
}
}
}
else
{
if (data.Flags & LineFlags::SubStart)
{
} else {
if(data.Flags & LineFlags::SubStart) {
string label = _labelManager->GetLabel(result.Address);
if (label.empty())
{
if(label.empty()) {
label = "sub start";
}
memcpy(data.Text, label.c_str(), label.size() + 1);
}
else if (data.Flags & LineFlags::BlockStart)
{
} else if(data.Flags & LineFlags::BlockStart) {
string label = (data.Flags & LineFlags::VerifiedData) ? "data" : "unidentified";
memcpy(data.Text, label.c_str(), label.size() + 1);
}
if (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd))
{
if (!(data.Flags & (LineFlags::ShowAsData | LineFlags::SubStart)))
{
if(data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) {
if(!(data.Flags & (LineFlags::ShowAsData | LineFlags::SubStart))) {
//For hidden blocks, give the start/end lines an address
data.Address = result.CpuAddress;
data.AbsoluteAddress = result.Address.Address;
@ -747,31 +600,25 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& d
return false;
}
int32_t Disassembler::SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition,
int32_t endPosition, bool searchBackwards)
int32_t Disassembler::SearchDisassembly(CpuType type, const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards)
{
auto lock = _disassemblyLock.AcquireSafe();
vector<DisassemblyResult>& source = _disassemblyResult[(int)type];
int step = searchBackwards ? -1 : 1;
CodeLineData lineData = {};
for (int i = startPosition; i != endPosition; i += step)
{
for(int i = startPosition; i != endPosition; i += step) {
GetLineData(type, i, lineData);
string line = lineData.Text;
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
if (line.find(searchString) != string::npos)
{
if(line.find(searchString) != string::npos) {
return i;
}
//Continue search from start/end of document
if (!searchBackwards && i == (int)(source.size() - 1))
{
if(!searchBackwards && i == (int)(source.size() - 1)) {
i = 0;
}
else if (searchBackwards && i == 0)
{
} else if(searchBackwards && i == 0) {
i = (int32_t)(source.size() - 1);
}
}

View file

@ -24,16 +24,16 @@ enum class CpuType : uint8_t;
struct DisassemblerSource
{
uint8_t* Data;
vector<DisassemblyInfo>* Cache;
uint8_t *Data;
vector<DisassemblyInfo> *Cache;
uint32_t Size;
};
class Disassembler
{
private:
MemoryManager* _memoryManager;
Console* _console;
MemoryManager *_memoryManager;
Console *_console;
Cpu* _cpu;
Spc* _spc;
Gsu* _gsu;
@ -42,17 +42,17 @@ private:
NecDsp* _necDsp;
Gameboy* _gameboy;
EmuSettings* _settings;
Debugger* _debugger;
Debugger *_debugger;
shared_ptr<CodeDataLogger> _cdl;
shared_ptr<LabelManager> _labelManager;
MemoryDumper* _memoryDumper;
MemoryDumper *_memoryDumper;
DisassemblerSource _sources[(int)SnesMemoryType::Register] = {};
vector<DisassemblyInfo> _disassemblyCache[(int)SnesMemoryType::Register];
SimpleLock _disassemblyLock;
vector<DisassemblyResult> _disassemblyResult[(int)DebugUtilities::GetLastCpuType() + 1];
bool _needDisassemble[(int)DebugUtilities::GetLastCpuType() + 1];
vector<DisassemblyResult> _disassemblyResult[(int)DebugUtilities::GetLastCpuType()+1];
bool _needDisassemble[(int)DebugUtilities::GetLastCpuType()+1];
void InitSource(SnesMemoryType type);
DisassemblerSource& GetSource(SnesMemoryType type);
@ -61,17 +61,16 @@ private:
public:
Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogger> cdl, Debugger* debugger);
uint32_t BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuType type);
uint32_t BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type);
void ResetPrgCache();
void InvalidateCache(AddressInfo addrInfo, CpuType type);
void Disassemble(CpuType cpuType);
DisassemblyInfo GetDisassemblyInfo(AddressInfo& info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type);
DisassemblyInfo GetDisassemblyInfo(AddressInfo &info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type);
void RefreshDisassembly(CpuType type);
uint32_t GetLineCount(CpuType type);
uint32_t GetLineIndex(CpuType type, uint32_t cpuAddress);
bool GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& data);
int32_t SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition,
bool searchBackwards);
bool GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data);
int32_t SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards);
};

View file

@ -18,12 +18,12 @@ DisassemblyInfo::DisassemblyInfo()
{
}
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, uint8_t cpuFlags, CpuType type)
DisassemblyInfo::DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags, CpuType type)
{
Initialize(opPointer, cpuFlags, type);
}
void DisassemblyInfo::Initialize(uint8_t* opPointer, uint8_t cpuFlags, CpuType type)
void DisassemblyInfo::Initialize(uint8_t *opPointer, uint8_t cpuFlags, CpuType type)
{
_cpuType = type;
_flags = cpuFlags;
@ -43,9 +43,8 @@ void DisassemblyInfo::Initialize(uint32_t cpuAddress, uint8_t cpuFlags, CpuType
_opSize = GetOpSize(_byteCode[0], _flags, _cpuType);
for (int i = 1; i < _opSize; i++)
{
_byteCode[i] = memoryDumper->GetMemoryValue(cpuMemType, cpuAddress + i);
for(int i = 1; i < _opSize; i++) {
_byteCode[i] = memoryDumper->GetMemoryValue(cpuMemType, cpuAddress+i);
}
_initialized = true;
@ -66,33 +65,25 @@ void DisassemblyInfo::Reset()
_initialized = false;
}
void DisassemblyInfo::GetDisassembly(string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings)
void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
{
switch (_cpuType)
{
switch(_cpuType) {
case CpuType::Sa1:
case CpuType::Cpu:
CpuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::Gsu: GsuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::Cx4: Cx4DisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::Gameboy: GameboyDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings);
break;
case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break;
case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break;
case CpuType::Gsu: GsuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break;
case CpuType::Cx4: Cx4DisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break;
case CpuType::Gameboy: GameboyDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break;
}
}
int32_t DisassemblyInfo::GetEffectiveAddress(Console* console, void* cpuState, CpuType cpuType)
int32_t DisassemblyInfo::GetEffectiveAddress(Console *console, void *cpuState, CpuType cpuType)
{
switch (_cpuType)
{
switch(_cpuType) {
case CpuType::Sa1:
case CpuType::Cpu:
return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState, cpuType);
@ -139,14 +130,12 @@ void DisassemblyInfo::GetByteCode(uint8_t copyBuffer[4])
memcpy(copyBuffer, _byteCode, _opSize);
}
void DisassemblyInfo::GetByteCode(string& out)
void DisassemblyInfo::GetByteCode(string &out)
{
FastString str;
for (int i = 0; i < _opSize; i++)
{
for(int i = 0; i < _opSize; i++) {
str.WriteAll('$', HexUtilities::ToHex(_byteCode[i]));
if (i < _opSize - 1)
{
if(i < _opSize - 1) {
str.Write(' ');
}
}
@ -155,8 +144,7 @@ void DisassemblyInfo::GetByteCode(string& out)
uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type)
{
switch (type)
{
switch(type) {
case CpuType::Sa1:
case CpuType::Cpu:
return CpuDisUtils::GetOpSize(opCode, flags);
@ -164,16 +152,11 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type)
case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode);
case CpuType::Gsu:
if (opCode >= 0x05 && opCode <= 0x0F)
{
if(opCode >= 0x05 && opCode <= 0x0F) {
return 2;
}
else if (opCode >= 0xA0 && opCode <= 0xAF)
{
} else if(opCode >= 0xA0 && opCode <= 0xAF) {
return 2;
}
else if (opCode >= 0xF0 && opCode <= 0xFF)
{
} else if(opCode >= 0xF0 && opCode <= 0xFF) {
return 3;
}
return 1;
@ -189,8 +172,7 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type)
//TODO: This is never called, removed?
bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type)
{
switch (type)
{
switch(type) {
case CpuType::Sa1:
case CpuType::Cpu:
return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL
@ -210,8 +192,7 @@ bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type)
bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type)
{
//RTS/RTI
switch (type)
{
switch(type) {
case CpuType::Sa1:
case CpuType::Cpu:
return opCode == 0x60 || opCode == 0x6B || opCode == 0x40;
@ -232,29 +213,20 @@ bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type)
bool DisassemblyInfo::IsUnconditionalJump()
{
uint8_t opCode = GetOpCode();
switch (_cpuType)
{
switch(_cpuType) {
case CpuType::Sa1:
case CpuType::Cpu:
if (opCode == 0x00 || opCode == 0x20 || opCode == 0x40 || opCode == 0x60 || opCode == 0x80 || opCode == 0x22 ||
opCode == 0xFC || opCode == 0x6B || opCode == 0x4C || opCode == 0x5C || opCode == 0x6C || opCode == 0x7C ||
opCode == 0x02)
{
if(opCode == 0x00 || opCode == 0x20 || opCode == 0x40 || opCode == 0x60 || opCode == 0x80 || opCode == 0x22 || opCode == 0xFC || opCode == 0x6B || opCode == 0x4C || opCode == 0x5C || opCode == 0x6C || opCode == 0x7C || opCode == 0x02) {
//Jumps, RTI, RTS, BRK, COP, etc., stop disassembling
return true;
}
else if (opCode == 0x28)
{
} else if(opCode == 0x28) {
//PLP, stop disassembling because the 8-bit/16-bit flags could change
return true;
}
return false;
case CpuType::Gameboy:
if (opCode == 0x18 || opCode == 0xC3 || opCode == 0xEA || opCode == 0xCD || opCode == 0xC9 || opCode == 0xD9 ||
opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF ||
opCode == 0xF7 || opCode == 0xFF)
{
if(opCode == 0x18 || opCode == 0xC3 || opCode == 0xEA || opCode == 0xCD || opCode == 0xC9 || opCode == 0xD9 || opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode == 0xF7 || opCode == 0xFF) {
return true;
}
return false;
@ -273,17 +245,13 @@ bool DisassemblyInfo::IsUnconditionalJump()
void DisassemblyInfo::UpdateCpuFlags(uint8_t& cpuFlags)
{
if (_cpuType == CpuType::Cpu || _cpuType == CpuType::Sa1)
{
if(_cpuType == CpuType::Cpu || _cpuType == CpuType::Sa1) {
uint8_t opCode = GetOpCode();
if (opCode == 0xC2)
{
if(opCode == 0xC2) {
//REP, update the flags and keep disassembling
uint8_t flags = GetByteCode()[1];
cpuFlags &= ~flags;
}
else if (opCode == 0xE2)
{
} else if(opCode == 0xE2) {
//SEP, update the flags and keep disassembling
uint8_t flags = GetByteCode()[1];
cpuFlags |= flags;
@ -291,16 +259,12 @@ void DisassemblyInfo::UpdateCpuFlags(uint8_t& cpuFlags)
}
}
uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryDumper* memoryDumper, SnesMemoryType memType,
uint8_t& valueSize)
uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryDumper *memoryDumper, SnesMemoryType memType, uint8_t &valueSize)
{
if ((_cpuType == CpuType::Spc || _cpuType == CpuType::Gameboy) || (_flags & ProcFlags::MemoryMode8))
{
if((_cpuType == CpuType::Spc || _cpuType == CpuType::Gameboy) || (_flags & ProcFlags::MemoryMode8)) {
valueSize = 1;
return memoryDumper->GetMemoryValue(memType, effectiveAddress);
}
else
{
} else {
valueSize = 2;
return memoryDumper->GetMemoryValueWord(memType, effectiveAddress);
}

View file

@ -20,15 +20,15 @@ private:
public:
DisassemblyInfo();
DisassemblyInfo(uint8_t* opPointer, uint8_t cpuFlags, CpuType type);
DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags, CpuType type);
void Initialize(uint8_t* opPointer, uint8_t cpuFlags, CpuType type);
void Initialize(uint8_t *opPointer, uint8_t cpuFlags, CpuType type);
void Initialize(uint32_t cpuAddress, uint8_t cpuFlags, CpuType type, MemoryDumper* memoryDumper);
bool IsInitialized();
bool IsValid(uint8_t cpuFlags);
void Reset();
void GetDisassembly(string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings);
void GetDisassembly(string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings* settings);
CpuType GetCpuType();
uint8_t GetOpCode();
@ -37,7 +37,7 @@ public:
uint8_t* GetByteCode();
void GetByteCode(uint8_t copyBuffer[4]);
void GetByteCode(string& out);
void GetByteCode(string &out);
static uint8_t GetOpSize(uint8_t opCode, uint8_t flags, CpuType type);
static bool IsJumpToSub(uint8_t opCode, CpuType type);
@ -46,7 +46,7 @@ public:
bool IsUnconditionalJump();
void UpdateCpuFlags(uint8_t& cpuFlags);
int32_t GetEffectiveAddress(Console* console, void* cpuState, CpuType type);
uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper* memoryDumper, SnesMemoryType memType,
uint8_t& valueSize);
int32_t GetEffectiveAddress(Console *console, void *cpuState, CpuType type);
uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper *memoryDumper, SnesMemoryType memType, uint8_t &valueSize);
};

View file

@ -5,21 +5,19 @@
#include "MessageManager.h"
#include "../Utilities/Serializer.h"
static constexpr uint8_t _transferByteCount[8] = {1, 2, 2, 4, 4, 4, 2, 4};
static constexpr uint8_t _transferByteCount[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
static constexpr uint8_t _transferOffset[8][4] = {
{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0}, {0, 0, 1, 1},
{0, 1, 2, 3}, {0, 1, 0, 1}, {0, 0, 0, 0}, {0, 0, 1, 1}
{ 0, 0, 0, 0 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 },
{ 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }
};
DmaController::DmaController(MemoryManager* memoryManager)
DmaController::DmaController(MemoryManager *memoryManager)
{
_memoryManager = memoryManager;
Reset();
for (int j = 0; j < 8; j++)
{
for (int i = 0; i <= 0x0A; i++)
{
for(int j = 0; j < 8; j++) {
for(int i = 0; i <= 0x0A; i++) {
Write(0x4300 | i | (j << 4), 0xFF);
}
}
@ -35,47 +33,36 @@ void DmaController::Reset()
_dmaPending = false;
_needToProcess = false;
for (int i = 0; i < 8; i++)
{
for(int i = 0; i < 8; i++) {
_channel[i].DmaActive = false;
}
}
void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA)
{
if (fromBtoA)
{
if (addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA))
{
if(fromBtoA) {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusB, false);
_memoryManager->WriteDma(addressBusA, valToWrite, true);
}
else
{
} else {
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
_memoryManager->IncMasterClock4();
_memoryManager->WriteDma(addressBusA, 0xFF, true);
}
}
else
{
if (addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA))
{
} else {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusA, true);
_memoryManager->WriteDma(addressBusB, valToWrite, false);
}
else
{
} else {
//WRAM->$2180 does not cause a write to occur
_memoryManager->IncMasterClock8();
}
}
}
void DmaController::RunDma(DmaChannelConfig& channel)
void DmaController::RunDma(DmaChannelConfig &channel)
{
if (!channel.DmaActive)
{
if(!channel.DmaActive) {
return;
}
@ -83,11 +70,10 @@ void DmaController::RunDma(DmaChannelConfig& channel)
_memoryManager->IncMasterClock8();
ProcessPendingTransfers();
const uint8_t* transferOffsets = _transferOffset[channel.TransferMode];
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
uint8_t i = 0;
do
{
do {
//Manual DMA transfers run to the end of the transfer when started
CopyDmaByte(
(channel.SrcBank << 16) | channel.SrcAddress,
@ -95,16 +81,14 @@ void DmaController::RunDma(DmaChannelConfig& channel)
channel.InvertDirection
);
if (!channel.FixedTransfer)
{
if(!channel.FixedTransfer) {
channel.SrcAddress += channel.Decrement ? -1 : 1;
}
channel.TransferSize--;
i++;
ProcessPendingTransfers();
}
while (channel.TransferSize > 0 && channel.DmaActive);
} while(channel.TransferSize > 0 && channel.DmaActive);
channel.DmaActive = false;
}
@ -113,37 +97,31 @@ bool DmaController::InitHdmaChannels()
{
_hdmaInitPending = false;
for (int i = 0; i < 8; i++)
{
for(int i = 0; i < 8; i++) {
//Reset internal flags on every frame, whether or not the channels are enabled
_channel[i].HdmaFinished = false;
_channel[i].DoTransfer = false;
//not resetting this causes graphical glitches in some games (Aladdin, Super Ghouls and Ghosts)
_channel[i].DoTransfer = false; //not resetting this causes graphical glitches in some games (Aladdin, Super Ghouls and Ghosts)
}
if (!_hdmaChannels)
{
if(!_hdmaChannels) {
//No channels are enabled, no more processing needs to be done
UpdateNeedToProcessFlag();
return false;
}
bool needSync = !HasActiveDmaChannel();
if (needSync)
{
if(needSync) {
SyncStartDma();
}
_memoryManager->IncMasterClock8();
for (int i = 0; i < 8; i++)
{
DmaChannelConfig& ch = _channel[i];
for(int i = 0; i < 8; i++) {
DmaChannelConfig &ch = _channel[i];
//Set DoTransfer to true for all channels if any HDMA channel is enabled
ch.DoTransfer = true;
if (_hdmaChannels & (1 << i))
{
if(_hdmaChannels & (1 << i)) {
//"1. Copy AAddress into Address."
ch.HdmaTableAddress = ch.SrcAddress;
ch.DmaActive = false;
@ -153,14 +131,12 @@ bool DmaController::InitHdmaChannels()
_memoryManager->IncMasterClock4();
ch.HdmaTableAddress++;
if (ch.HdmaLineCounterAndRepeat == 0)
{
if(ch.HdmaLineCounterAndRepeat == 0) {
ch.HdmaFinished = true;
}
//3. Load Indirect Address, if necessary.
if (ch.HdmaIndirectAddressing)
{
if(ch.HdmaIndirectAddressing) {
uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4();
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
@ -170,8 +146,7 @@ bool DmaController::InitHdmaChannels()
}
}
if (needSync)
{
if(needSync) {
SyncEndDma();
}
@ -179,17 +154,15 @@ bool DmaController::InitHdmaChannels()
return true;
}
void DmaController::RunHdmaTransfer(DmaChannelConfig& channel)
void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
{
const uint8_t* transferOffsets = _transferOffset[channel.TransferMode];
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
uint8_t transferByteCount = _transferByteCount[channel.TransferMode];
channel.DmaActive = false;
uint8_t i = 0;
if (channel.HdmaIndirectAddressing)
{
do
{
if(channel.HdmaIndirectAddressing) {
do {
CopyDmaByte(
(channel.HdmaBank << 16) | channel.TransferSize,
0x2100 | (channel.DestAddress + transferOffsets[i]),
@ -197,13 +170,9 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig& channel)
);
channel.TransferSize++;
i++;
}
while (i < transferByteCount);
}
else
{
do
{
} while(i < transferByteCount);
} else {
do {
CopyDmaByte(
(channel.SrcBank << 16) | channel.HdmaTableAddress,
0x2100 | (channel.DestAddress + transferOffsets[i]),
@ -211,8 +180,7 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig& channel)
);
channel.HdmaTableAddress++;
i++;
}
while (i < transferByteCount);
} while(i < transferByteCount);
}
}
@ -227,16 +195,13 @@ void DmaController::SyncEndDma()
{
//"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause"
uint8_t cpuSpeed = _memoryManager->GetCpuSpeed();
_memoryManager->IncrementMasterClockValue(
cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed));
_memoryManager->IncrementMasterClockValue(cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed));
}
bool DmaController::HasActiveDmaChannel()
{
for (int i = 0; i < 8; i++)
{
if (_channel[i].DmaActive)
{
for(int i = 0; i < 8; i++) {
if(_channel[i].DmaActive) {
return true;
}
}
@ -247,15 +212,13 @@ bool DmaController::ProcessHdmaChannels()
{
_hdmaPending = false;
if (!_hdmaChannels)
{
if(!_hdmaChannels) {
UpdateNeedToProcessFlag();
return false;
}
bool needSync = !HasActiveDmaChannel();
if (needSync)
{
if(needSync) {
SyncStartDma();
}
_memoryManager->IncMasterClock8();
@ -263,24 +226,20 @@ bool DmaController::ProcessHdmaChannels()
uint8_t originalActiveChannel = _activeChannel;
//Run all the DMA transfers for each channel first, before fetching data for the next scanline
for (int i = 0; i < 8; i++)
{
DmaChannelConfig& ch = _channel[i];
if ((_hdmaChannels & (1 << i)) == 0)
{
for(int i = 0; i < 8; i++) {
DmaChannelConfig &ch = _channel[i];
if((_hdmaChannels & (1 << i)) == 0) {
continue;
}
ch.DmaActive = false;
if (ch.HdmaFinished)
{
if(ch.HdmaFinished) {
continue;
}
//1. If DoTransfer is false, skip to step 3.
if (ch.DoTransfer)
{
if(ch.DoTransfer) {
//2. For the number of bytes (1, 2, or 4) required for this Transfer Mode...
_activeChannel = DmaController::HdmaChannelFlag | i;
RunHdmaTransfer(ch);
@ -288,11 +247,9 @@ bool DmaController::ProcessHdmaChannels()
}
//Update the channel's state & fetch data for the next scanline
for (int i = 0; i < 8; i++)
{
DmaChannelConfig& ch = _channel[i];
if ((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished)
{
for(int i = 0; i < 8; i++) {
DmaChannelConfig &ch = _channel[i];
if((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished) {
continue;
}
@ -308,24 +265,19 @@ bool DmaController::ProcessHdmaChannels()
_memoryManager->IncMasterClock4();
//5. If Line Counter is zero...
if ((ch.HdmaLineCounterAndRepeat & 0x7F) == 0)
{
if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) {
ch.HdmaLineCounterAndRepeat = newCounter;
ch.HdmaTableAddress++;
//"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)."
if (ch.HdmaIndirectAddressing)
{
if (ch.HdmaLineCounterAndRepeat == 0 && IsLastActiveHdmaChannel(i))
{
if(ch.HdmaIndirectAddressing) {
if(ch.HdmaLineCounterAndRepeat == 0 && IsLastActiveHdmaChannel(i)) {
//"One oddity: if $43xA is 0 and this is the last active HDMA channel for this scanline, only load one byte for Address,
//and use the $00 for the low byte.So Address ends up incremented one less than otherwise expected, and one less CPU Cycle is used."
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4();
ch.TransferSize = (msb << 8);
}
else
{
} else {
//"If a new indirect address is required, 16 master cycles are taken to load it."
uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4();
@ -338,8 +290,7 @@ bool DmaController::ProcessHdmaChannels()
}
//"c. If $43xA is zero, terminate this HDMA channel for this frame. The bit in $420c is not cleared, though, so it may be automatically restarted next frame."
if (ch.HdmaLineCounterAndRepeat == 0)
{
if(ch.HdmaLineCounterAndRepeat == 0) {
ch.HdmaFinished = true;
}
@ -348,8 +299,7 @@ bool DmaController::ProcessHdmaChannels()
}
}
if (needSync)
{
if(needSync) {
//If we ran a HDMA transfer, sync
SyncEndDma();
}
@ -362,10 +312,8 @@ bool DmaController::ProcessHdmaChannels()
bool DmaController::IsLastActiveHdmaChannel(uint8_t channel)
{
for (int i = channel + 1; i < 8; i++)
{
if ((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished)
{
for(int i = channel + 1; i < 8; i++) {
if((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished) {
return false;
}
}
@ -380,8 +328,7 @@ void DmaController::UpdateNeedToProcessFlag()
void DmaController::BeginHdmaTransfer()
{
if (_hdmaChannels)
{
if(_hdmaChannels) {
_hdmaPending = true;
UpdateNeedToProcessFlag();
}
@ -395,37 +342,28 @@ void DmaController::BeginHdmaInit()
bool DmaController::ProcessPendingTransfers()
{
if (!_needToProcess)
{
if(!_needToProcess) {
return false;
}
if (_dmaStartDelay)
{
if(_dmaStartDelay) {
_dmaStartDelay = false;
return false;
}
if (_hdmaPending)
{
if(_hdmaPending) {
return ProcessHdmaChannels();
}
else if (_hdmaInitPending)
{
} else if(_hdmaInitPending) {
return InitHdmaChannels();
}
else if (_dmaPending)
{
} else if(_dmaPending) {
_dmaPending = false;
SyncStartDma();
_memoryManager->IncMasterClock8();
ProcessPendingTransfers();
for (int i = 0; i < 8; i++)
{
if (_channel[i].DmaActive)
{
for(int i = 0; i < 8; i++) {
if(_channel[i].DmaActive) {
_activeChannel = i;
RunDma(_channel[i]);
}
@ -442,21 +380,16 @@ bool DmaController::ProcessPendingTransfers()
void DmaController::Write(uint16_t addr, uint8_t value)
{
switch (addr)
{
case 0x420B:
{
switch(addr) {
case 0x420B: {
//MDMAEN - DMA Enable
for (int i = 0; i < 8; i++)
{
if (value & (1 << i))
{
for(int i = 0; i < 8; i++) {
if(value & (1 << i)) {
_channel[i].DmaActive = true;
}
}
if (value)
{
if(value) {
_dmaPending = true;
_dmaStartDelay = true;
UpdateNeedToProcessFlag();
@ -469,17 +402,10 @@ void DmaController::Write(uint16_t addr, uint8_t value)
_hdmaChannels = value;
break;
case 0x4300:
case 0x4310:
case 0x4320:
case 0x4330:
case 0x4340:
case 0x4350:
case 0x4360:
case 0x4370:
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
{
//DMAPx - DMA Control for Channel x
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.InvertDirection = (value & 0x80) != 0;
channel.HdmaIndirectAddressing = (value & 0x40) != 0;
channel.UnusedFlag = (value & 0x20) != 0;
@ -489,192 +415,101 @@ void DmaController::Write(uint16_t addr, uint8_t value)
break;
}
case 0x4301:
case 0x4311:
case 0x4321:
case 0x4331:
case 0x4341:
case 0x4351:
case 0x4361:
case 0x4371:
case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371:
{
//BBADx - DMA Destination Register for Channel x
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.DestAddress = value;
break;
}
case 0x4302:
case 0x4312:
case 0x4322:
case 0x4332:
case 0x4342:
case 0x4352:
case 0x4362:
case 0x4372:
case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcAddress = (channel.SrcAddress & 0xFF00) | value;
break;
}
case 0x4303:
case 0x4313:
case 0x4323:
case 0x4333:
case 0x4343:
case 0x4353:
case 0x4363:
case 0x4373:
case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcAddress = (channel.SrcAddress & 0xFF) | (value << 8);
break;
}
case 0x4304:
case 0x4314:
case 0x4324:
case 0x4334:
case 0x4344:
case 0x4354:
case 0x4364:
case 0x4374:
case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcBank = value;
break;
}
case 0x4305:
case 0x4315:
case 0x4325:
case 0x4335:
case 0x4345:
case 0x4355:
case 0x4365:
case 0x4375:
case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.TransferSize = (channel.TransferSize & 0xFF00) | value;
break;
}
case 0x4306:
case 0x4316:
case 0x4326:
case 0x4336:
case 0x4346:
case 0x4356:
case 0x4366:
case 0x4376:
case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.TransferSize = (channel.TransferSize & 0xFF) | (value << 8);
break;
}
case 0x4307:
case 0x4317:
case 0x4327:
case 0x4337:
case 0x4347:
case 0x4357:
case 0x4367:
case 0x4377:
case 0x4307: case 0x4317: case 0x4327: case 0x4337: case 0x4347: case 0x4357: case 0x4367: case 0x4377:
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.HdmaBank = value;
break;
}
case 0x4308:
case 0x4318:
case 0x4328:
case 0x4338:
case 0x4348:
case 0x4358:
case 0x4368:
case 0x4378:
case 0x4308: case 0x4318: case 0x4328: case 0x4338: case 0x4348: case 0x4358: case 0x4368: case 0x4378:
{
//A2AxL - HDMA Table Address low byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.HdmaTableAddress = (channel.HdmaTableAddress & 0xFF00) | value;
break;
}
case 0x4309:
case 0x4319:
case 0x4329:
case 0x4339:
case 0x4349:
case 0x4359:
case 0x4369:
case 0x4379:
case 0x4309: case 0x4319: case 0x4329: case 0x4339: case 0x4349: case 0x4359: case 0x4369: case 0x4379:
{
//A2AxH - HDMA Table Address high byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.HdmaTableAddress = (value << 8) | (channel.HdmaTableAddress & 0xFF);
break;
}
case 0x430A:
case 0x431A:
case 0x432A:
case 0x433A:
case 0x434A:
case 0x435A:
case 0x436A:
case 0x437A:
case 0x430A: case 0x431A: case 0x432A: case 0x433A: case 0x434A: case 0x435A: case 0x436A: case 0x437A:
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.HdmaLineCounterAndRepeat = value;
break;
}
case 0x430B:
case 0x431B:
case 0x432B:
case 0x433B:
case 0x434B:
case 0x435B:
case 0x436B:
case 0x437B:
case 0x430F:
case 0x431F:
case 0x432F:
case 0x433F:
case 0x434F:
case 0x435F:
case 0x436F:
case 0x437F:
case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B:
case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F:
{
//UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.UnusedByte = value;
}
}
}
uint8_t DmaController::Read(uint16_t addr)
{
switch (addr)
{
case 0x4300:
case 0x4310:
case 0x4320:
case 0x4330:
case 0x4340:
case 0x4350:
case 0x4360:
case 0x4370:
switch(addr) {
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
{
//DMAPx - DMA Control for Channel x
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return (
(channel.InvertDirection ? 0x80 : 0) |
(channel.HdmaIndirectAddressing ? 0x40 : 0) |
@ -685,164 +520,81 @@ uint8_t DmaController::Read(uint16_t addr)
);
}
case 0x4301:
case 0x4311:
case 0x4321:
case 0x4331:
case 0x4341:
case 0x4351:
case 0x4361:
case 0x4371:
case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371:
{
//BBADx - DMA Destination Register for Channel x
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.DestAddress;
}
case 0x4302:
case 0x4312:
case 0x4322:
case 0x4332:
case 0x4342:
case 0x4352:
case 0x4362:
case 0x4372:
case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.SrcAddress & 0xFF;
}
case 0x4303:
case 0x4313:
case 0x4323:
case 0x4333:
case 0x4343:
case 0x4353:
case 0x4363:
case 0x4373:
case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return (channel.SrcAddress >> 8) & 0xFF;
}
case 0x4304:
case 0x4314:
case 0x4324:
case 0x4334:
case 0x4344:
case 0x4354:
case 0x4364:
case 0x4374:
case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374:
{
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.SrcBank;
}
case 0x4305:
case 0x4315:
case 0x4325:
case 0x4335:
case 0x4345:
case 0x4355:
case 0x4365:
case 0x4375:
case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.TransferSize & 0xFF;
}
case 0x4306:
case 0x4316:
case 0x4326:
case 0x4336:
case 0x4346:
case 0x4356:
case 0x4366:
case 0x4376:
case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return (channel.TransferSize >> 8) & 0xFF;
}
case 0x4307:
case 0x4317:
case 0x4327:
case 0x4337:
case 0x4347:
case 0x4357:
case 0x4367:
case 0x4377:
case 0x4307: case 0x4317: case 0x4327: case 0x4337: case 0x4347: case 0x4357: case 0x4367: case 0x4377:
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.HdmaBank;
}
case 0x4308:
case 0x4318:
case 0x4328:
case 0x4338:
case 0x4348:
case 0x4358:
case 0x4368:
case 0x4378:
case 0x4308: case 0x4318: case 0x4328: case 0x4338: case 0x4348: case 0x4358: case 0x4368: case 0x4378:
{
//A2AxL - HDMA Table Address low byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.HdmaTableAddress & 0xFF;
}
case 0x4309:
case 0x4319:
case 0x4329:
case 0x4339:
case 0x4349:
case 0x4359:
case 0x4369:
case 0x4379:
case 0x4309: case 0x4319: case 0x4329: case 0x4339: case 0x4349: case 0x4359: case 0x4369: case 0x4379:
{
//A2AxH - HDMA Table Address high byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return (channel.HdmaTableAddress >> 8) & 0xFF;
}
case 0x430A:
case 0x431A:
case 0x432A:
case 0x433A:
case 0x434A:
case 0x435A:
case 0x436A:
case 0x437A:
case 0x430A: case 0x431A: case 0x432A: case 0x433A: case 0x434A: case 0x435A: case 0x436A: case 0x437A:
{
//DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
return channel.HdmaLineCounterAndRepeat;
}
case 0x430B:
case 0x431B:
case 0x432B:
case 0x433B:
case 0x434B:
case 0x435B:
case 0x436B:
case 0x437B:
case 0x430F:
case 0x431F:
case 0x432F:
case 0x433F:
case 0x434F:
case 0x435F:
case 0x436F:
case 0x437F:
case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B:
case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F:
{
//UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return channel.UnusedByte;
}
}
return _memoryManager->GetOpenBus();
}
@ -857,11 +609,10 @@ DmaChannelConfig DmaController::GetChannelConfig(uint8_t channel)
return _channel[channel];
}
void DmaController::Serialize(Serializer& s)
void DmaController::Serialize(Serializer &s)
{
s.Stream(_hdmaPending, _hdmaChannels, _dmaPending, _dmaStartClock, _hdmaInitPending, _dmaStartDelay, _needToProcess);
for (int i = 0; i < 8; i++)
{
for(int i = 0; i < 8; i++) {
s.Stream(
_channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer,
_channel[i].HdmaBank, _channel[i].HdmaFinished, _channel[i].HdmaIndirectAddressing,

View file

@ -22,13 +22,13 @@ private:
uint8_t _activeChannel = 0; //Used by debugger's event viewer
DmaChannelConfig _channel[8] = {};
MemoryManager* _memoryManager;
MemoryManager *_memoryManager;
void CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA);
void RunDma(DmaChannelConfig& channel);
void RunDma(DmaChannelConfig &channel);
void RunHdmaTransfer(DmaChannelConfig& channel);
void RunHdmaTransfer(DmaChannelConfig &channel);
bool ProcessHdmaChannels();
bool IsLastActiveHdmaChannel(uint8_t channel);
bool InitHdmaChannels();
@ -40,7 +40,7 @@ private:
bool HasActiveDmaChannel();
public:
DmaController(MemoryManager* memoryManager);
DmaController(MemoryManager *memoryManager);
void Reset();
@ -55,5 +55,5 @@ public:
uint8_t GetActiveChannel();
DmaChannelConfig GetChannelConfig(uint8_t channel);
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

@ -18,50 +18,34 @@ protected:
int _yScale;
virtual void InternalDraw() = 0;
__forceinline void DrawPixel(uint32_t x, uint32_t y, int color)
{
if (x < _overscan.Left || x >= (256 - _overscan.Right) || y < _overscan.Top || y >= (239 - _overscan.Bottom))
{
if(x < _overscan.Left || x >= (256 - _overscan.Right) || y < _overscan.Top || y >= (239 - _overscan.Bottom)) {
//Out of bounds, skip drawing
return;
}
uint32_t alpha = (color & 0xFF000000);
if (alpha > 0)
{
if (_yScale == 1)
{
if (alpha != 0xFF000000)
{
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)],
(uint8_t*)&color);
if(alpha > 0) {
if(_yScale == 1) {
if(alpha != 0xFF000000) {
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)], (uint8_t*)&color);
} else {
_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)] = color;
}
else
{
_argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)] = color;
}
}
else
{
int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1) * _xScale) - (int)(x * _xScale);
} else {
int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1)*_xScale) - (int)(x*_xScale);
x = (int)(x * (_useIntegerScaling ? _yScale : _xScale));
y = (int)(y * _yScale);
int top = (int)(_overscan.Top * _yScale);
int left = (int)(_overscan.Left * _xScale);
for (int i = 0; i < _yScale; i++)
{
for (int j = 0; j < xPixelCount; j++)
{
if (alpha != 0xFF000000)
{
BlendColors((uint8_t*)&_argbBuffer[(y - top) * _lineWidth + i * _lineWidth + (x - left) + j],
(uint8_t*)&color);
}
else
{
_argbBuffer[(y - top) * _lineWidth + i * _lineWidth + (x - left) + j] = color;
for(int i = 0; i < _yScale; i++) {
for(int j = 0; j < xPixelCount; j++) {
if(alpha != 0xFF000000) {
BlendColors((uint8_t*)&_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left)+j], (uint8_t*)&color);
} else {
_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left) +j] = color;
}
}
}
@ -91,10 +75,9 @@ public:
{
}
void Draw(uint32_t* argbBuffer, OverscanDimensions& overscan, uint32_t lineWidth, uint32_t frameNumber)
{
if (_startFrame <= frameNumber)
void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan, uint32_t lineWidth, uint32_t frameNumber)
{
if(_startFrame <= frameNumber) {
_argbBuffer = argbBuffer;
_overscan = overscan;
_lineWidth = lineWidth;

View file

@ -16,24 +16,18 @@ protected:
int dy = abs(_y2 - y), sy = y < _y2 ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
while (true)
{
while(true) {
DrawPixel(x, y, _color);
if (x == _x2 && y == _y2)
{
if(x == _x2 && y == _y2) {
break;
}
e2 = err;
if (e2 > -dx)
{
err -= dy;
x += sx;
if(e2 > -dx) {
err -= dy; x += sx;
}
if (e2 < dy)
{
err += dx;
y += sy;
if(e2 < dy) {
err += dx; y += sy;
}
}
}

View file

@ -11,25 +11,18 @@ private:
protected:
void InternalDraw()
{
if (_fill)
{
for (int j = 0; j < _height; j++)
{
for (int i = 0; i < _width; i++)
{
if(_fill) {
for(int j = 0; j < _height; j++) {
for(int i = 0; i < _width; i++) {
DrawPixel(_x + i, _y + j, _color);
}
}
}
else
{
for (int i = 0; i < _width; i++)
{
} else {
for(int i = 0; i < _width; i++) {
DrawPixel(_x + i, _y, _color);
DrawPixel(_x + i, _y + _height - 1, _color);
}
for (int i = 1; i < _height - 1; i++)
{
for(int i = 1; i < _height - 1; i++) {
DrawPixel(_x, _y + i, _color);
DrawPixel(_x + _width - 1, _y + i, _color);
}
@ -40,13 +33,11 @@ public:
DrawRectangleCommand(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame) :
DrawCommand(startFrame, frameCount), _x(x), _y(y), _width(width), _height(height), _color(color), _fill(fill)
{
if (width < 0)
{
if(width < 0) {
_x += width + 1;
_width = -width;
}
if (height < 0)
{
if(height < 0) {
_y += height + 1;
_height = -height;
}

View file

@ -5,15 +5,13 @@
class DrawScreenBufferCommand : public DrawCommand
{
private:
uint32_t _screenBuffer[256 * 240];
uint32_t _screenBuffer[256*240];
protected:
void InternalDraw()
{
for (int y = 0; y < 240; y++)
{
for (int x = 0; x < 256; x++)
{
for(int y = 0; y < 240; y++) {
for(int x = 0; x < 256; x++) {
DrawPixel(x, y, _screenBuffer[(y << 8) + x]);
}
}

View file

@ -14,98 +14,98 @@ private:
6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar
3, 64, 64, 64, 64, 64, 0, 64,
5, 80, 80, 80, 0, 0, 0, 0,
6, 80, 80, 248, 80, 248, 80, 80,
6, 32, 120, 160, 112, 40, 240, 32,
6, 64, 168, 80, 32, 80, 168, 16,
6, 96, 144, 160, 64, 168, 144, 104,
6, 80, 80,248, 80,248, 80, 80,
6, 32,120,160,112, 40,240, 32,
6, 64,168, 80, 32, 80,168, 16,
6, 96,144,160, 64,168,144,104,
3, 64, 64, 0, 0, 0, 0, 0,
4, 32, 64, 64, 64, 64, 64, 32,
4, 64, 32, 32, 32, 32, 32, 64,
6, 0, 80, 32, 248, 32, 80, 0,
6, 0, 32, 32, 248, 32, 32, 0,
3, 0, 0, 0, 0, 0, 64, 128,
5, 0, 0, 0, 240, 0, 0, 0,
6, 0, 80, 32,248, 32, 80, 0,
6, 0, 32, 32,248, 32, 32, 0,
3, 0, 0, 0, 0, 0, 64,128,
5, 0, 0, 0,240, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 64,
5, 16, 16, 32, 32, 32, 64, 64,
6, 112, 136, 136, 136, 136, 136, 112, // 0x30 - 0
6,112,136,136,136,136,136,112, // 0x30 - 0
6, 32, 96, 32, 32, 32, 32, 32,
6, 112, 136, 8, 48, 64, 128, 248,
6, 112, 136, 8, 48, 8, 136, 112,
6, 16, 48, 80, 144, 248, 16, 16,
6, 248, 128, 128, 240, 8, 8, 240,
6, 48, 64, 128, 240, 136, 136, 112,
6, 248, 8, 16, 16, 32, 32, 32,
6, 112, 136, 136, 112, 136, 136, 112,
6, 112, 136, 136, 120, 8, 16, 96,
6,112,136, 8, 48, 64,128,248,
6,112,136, 8, 48, 8,136,112,
6, 16, 48, 80,144,248, 16, 16,
6,248,128,128,240, 8, 8,240,
6, 48, 64,128,240,136,136,112,
6,248, 8, 16, 16, 32, 32, 32,
6,112,136,136,112,136,136,112,
6,112,136,136,120, 8, 16, 96,
3, 0, 0, 64, 0, 0, 64, 0,
3, 0, 0, 64, 0, 0, 64, 128,
4, 0, 32, 64, 128, 64, 32, 0,
5, 0, 0, 240, 0, 240, 0, 0,
4, 0, 128, 64, 32, 64, 128, 0,
6, 112, 136, 8, 16, 32, 0, 32, // 0x3F - ?
6, 112, 136, 136, 184, 176, 128, 112, // 0x40 - @
6, 112, 136, 136, 248, 136, 136, 136, // 0x41 - A
6, 240, 136, 136, 240, 136, 136, 240,
6, 112, 136, 128, 128, 128, 136, 112,
6, 224, 144, 136, 136, 136, 144, 224,
6, 248, 128, 128, 240, 128, 128, 248,
6, 248, 128, 128, 240, 128, 128, 128,
6, 112, 136, 128, 184, 136, 136, 120,
6, 136, 136, 136, 248, 136, 136, 136,
4, 224, 64, 64, 64, 64, 64, 224,
6, 8, 8, 8, 8, 8, 136, 112,
6, 136, 144, 160, 192, 160, 144, 136,
6, 128, 128, 128, 128, 128, 128, 248,
6, 136, 216, 168, 168, 136, 136, 136,
6, 136, 136, 200, 168, 152, 136, 136,
7, 48, 72, 132, 132, 132, 72, 48,
6, 240, 136, 136, 240, 128, 128, 128,
6, 112, 136, 136, 136, 168, 144, 104,
6, 240, 136, 136, 240, 144, 136, 136,
6, 112, 136, 128, 112, 8, 136, 112,
6, 248, 32, 32, 32, 32, 32, 32,
6, 136, 136, 136, 136, 136, 136, 112,
6, 136, 136, 136, 80, 80, 32, 32,
6, 136, 136, 136, 136, 168, 168, 80,
6, 136, 136, 80, 32, 80, 136, 136,
6, 136, 136, 80, 32, 32, 32, 32,
6, 248, 8, 16, 32, 64, 128, 248,
3, 192, 128, 128, 128, 128, 128, 192,
3, 0, 0, 64, 0, 0, 64,128,
4, 0, 32, 64,128, 64, 32, 0,
5, 0, 0,240, 0,240, 0, 0,
4, 0,128, 64, 32, 64,128, 0,
6,112,136, 8, 16, 32, 0, 32, // 0x3F - ?
6,112,136,136,184,176,128,112, // 0x40 - @
6,112,136,136,248,136,136,136, // 0x41 - A
6,240,136,136,240,136,136,240,
6,112,136,128,128,128,136,112,
6,224,144,136,136,136,144,224,
6,248,128,128,240,128,128,248,
6,248,128,128,240,128,128,128,
6,112,136,128,184,136,136,120,
6,136,136,136,248,136,136,136,
4,224, 64, 64, 64, 64, 64,224,
6, 8, 8, 8, 8, 8,136,112,
6,136,144,160,192,160,144,136,
6,128,128,128,128,128,128,248,
6,136,216,168,168,136,136,136,
6,136,136,200,168,152,136,136,
7, 48, 72,132,132,132, 72, 48,
6,240,136,136,240,128,128,128,
6,112,136,136,136,168,144,104,
6,240,136,136,240,144,136,136,
6,112,136,128,112, 8,136,112,
6,248, 32, 32, 32, 32, 32, 32,
6,136,136,136,136,136,136,112,
6,136,136,136, 80, 80, 32, 32,
6,136,136,136,136,168,168, 80,
6,136,136, 80, 32, 80,136,136,
6,136,136, 80, 32, 32, 32, 32,
6,248, 8, 16, 32, 64,128,248,
3,192,128,128,128,128,128,192,
5, 64, 64, 32, 32, 32, 16, 16,
3, 192, 64, 64, 64, 64, 64, 192,
4, 64, 160, 0, 0, 0, 0, 0,
6, 0, 0, 0, 0, 0, 0, 248,
3, 128, 64, 0, 0, 0, 0, 0,
5, 0, 0, 96, 16, 112, 144, 112, // 0x61 - a
5, 128, 128, 224, 144, 144, 144, 224,
5, 0, 0, 112, 128, 128, 128, 112,
5, 16, 16, 112, 144, 144, 144, 112,
5, 0, 0, 96, 144, 240, 128, 112,
5, 48, 64, 224, 64, 64, 64, 64,
5, 0, 112, 144, 144, 112, 16, 224,
5, 128, 128, 224, 144, 144, 144, 144,
2, 128, 0, 128, 128, 128, 128, 128,
4, 32, 0, 32, 32, 32, 32, 192,
5, 128, 128, 144, 160, 192, 160, 144,
2, 128, 128, 128, 128, 128, 128, 128,
6, 0, 0, 208, 168, 168, 168, 168,
5, 0, 0, 224, 144, 144, 144, 144,
5, 0, 0, 96, 144, 144, 144, 96,
5, 0, 224, 144, 144, 224, 128, 128,
5, 0, 112, 144, 144, 112, 16, 16,
5, 0, 0, 176, 192, 128, 128, 128,
5, 0, 0, 112, 128, 96, 16, 224,
4, 64, 64, 224, 64, 64, 64, 32,
5, 0, 0, 144, 144, 144, 144, 112,
5, 0, 0, 144, 144, 144, 160, 192,
6, 0, 0, 136, 136, 168, 168, 80,
5, 0, 0, 144, 144, 96, 144, 144,
5, 0, 144, 144, 144, 112, 16, 96,
5, 0, 0, 240, 32, 64, 128, 240,
4, 32, 64, 64, 128, 64, 64, 32,
3,192, 64, 64, 64, 64, 64,192,
4, 64,160, 0, 0, 0, 0, 0,
6, 0, 0, 0, 0, 0, 0,248,
3,128, 64, 0, 0, 0, 0, 0,
5, 0, 0, 96, 16,112,144,112, // 0x61 - a
5,128,128,224,144,144,144,224,
5, 0, 0,112,128,128,128,112,
5, 16, 16,112,144,144,144,112,
5, 0, 0, 96,144,240,128,112,
5, 48, 64,224, 64, 64, 64, 64,
5, 0,112,144,144,112, 16,224,
5,128,128,224,144,144,144,144,
2,128, 0,128,128,128,128,128,
4, 32, 0, 32, 32, 32, 32,192,
5,128,128,144,160,192,160,144,
2,128,128,128,128,128,128,128,
6, 0, 0,208,168,168,168,168,
5, 0, 0,224,144,144,144,144,
5, 0, 0, 96,144,144,144, 96,
5, 0,224,144,144,224,128,128,
5, 0,112,144,144,112, 16, 16,
5, 0, 0,176,192,128,128,128,
5, 0, 0,112,128, 96, 16,224,
4, 64, 64,224, 64, 64, 64, 32,
5, 0, 0,144,144,144,144,112,
5, 0, 0,144,144,144,160,192,
6, 0, 0,136,136,168,168, 80,
5, 0, 0,144,144, 96,144,144,
5, 0,144,144,144,112, 16, 96,
5, 0, 0,240, 32, 64,128,240,
4, 32, 64, 64,128, 64, 64, 32,
3, 64, 64, 64, 64, 64, 64, 64,
4, 128, 64, 64, 32, 64, 64, 128,
6, 0, 104, 176, 0, 0, 0, 0
4,128, 64, 64, 32, 64, 64,128,
6, 0,104,176, 0, 0, 0, 0
};
int GetCharNumber(char ch)
@ -125,35 +125,24 @@ protected:
int startX = (int)(_x * _xScale / _yScale);
int x = startX;
int y = _y;
for (char c : _text)
{
if (c == '\n')
{
for(char c : _text) {
if(c == '\n') {
x = startX;
y += 9;
}
else if (c == '\t')
{
} else if(c == '\t') {
x += (_tabSpace - (((x - startX) / 8) % _tabSpace)) * 8;
}
else
{
} else {
int ch = GetCharNumber(c);
int width = GetCharWidth(c);
int rowOffset = (c == 'y' || c == 'g' || c == 'p' || c == 'q') ? 1 : 0;
for (int j = 0; j < 8; j++)
{
uint8_t rowData = ((j == 7 && rowOffset == 0) || (j == 0 && rowOffset == 1))
? 0
: _font[ch * 8 + 1 + j - rowOffset];
for (int i = 0; i < width; i++)
{
for(int j = 0; j < 8; j++) {
uint8_t rowData = ((j == 7 && rowOffset == 0) || (j == 0 && rowOffset == 1)) ? 0 : _font[ch * 8 + 1 + j - rowOffset];
for(int i = 0; i < width; i++) {
int drawFg = (rowData >> (7 - i)) & 0x01;
DrawPixel(x + i, y + j, drawFg ? _color : _backColor);
}
}
for (int i = 0; i < width; i++)
{
for(int i = 0; i < width; i++) {
DrawPixel(x + i, y - 1, _backColor);
}
x += width;

View file

@ -16,9 +16,7 @@
DummyCpu::DummyCpu(Console* console, CpuType type)
{
_console = console;
_memoryMappings = type == CpuType::Cpu
? console->GetMemoryManager()->GetMemoryMappings()
: console->GetCartridge()->GetSa1()->GetMemoryMappings();
_memoryMappings = type == CpuType::Cpu ? console->GetMemoryManager()->GetMemoryMappings() : console->GetCartridge()->GetSa1()->GetMemoryMappings();
_dmaController = nullptr;
_memoryManager = nullptr;
}
@ -35,7 +33,7 @@ void DummyCpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
LogWrite(addr, value);
}
void DummyCpu::SetDummyState(CpuState& state)
void DummyCpu::SetDummyState(CpuState &state)
{
_state = state;
_state.StopState = CpuStopState::Running;
@ -67,13 +65,13 @@ void DummyCpu::LogWrite(uint32_t addr, uint8_t value)
_writeCounter++;
}
void DummyCpu::GetWriteInfo(uint32_t index, uint32_t& addr, uint8_t& value)
void DummyCpu::GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value)
{
addr = _writeAddresses[index];
value = _writeValue[index];
}
void DummyCpu::GetReadInfo(uint32_t index, uint32_t& addr, uint8_t& value)
void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value)
{
addr = _readAddresses[index];
value = _readValue[index];

View file

@ -12,7 +12,7 @@
#include "Spc.h"
DummySpc::DummySpc(uint8_t* spcRam, SpcState& state)
DummySpc::DummySpc(uint8_t *spcRam, SpcState &state)
{
_ram = spcRam;
@ -37,11 +37,9 @@ DummySpc::~DummySpc()
void DummySpc::Step()
{
do
{
do {
ProcessCycle();
}
while (_opStep != SpcOpStep::ReadOpCode);
} while(_opStep != SpcOpStep::ReadOpCode);
}
uint32_t DummySpc::GetWriteCount()
@ -68,13 +66,13 @@ void DummySpc::LogWrite(uint32_t addr, uint8_t value)
_writeCounter++;
}
void DummySpc::GetWriteInfo(uint32_t index, uint32_t& addr, uint8_t& value)
void DummySpc::GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value)
{
addr = _writeAddresses[index];
value = _writeValue[index];
}
void DummySpc::GetReadInfo(uint32_t index, uint32_t& addr, uint8_t& value)
void DummySpc::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value)
{
addr = _readAddresses[index];
value = _readValue[index];

View file

@ -31,19 +31,15 @@ uint32_t EmuSettings::GetVersion()
string EmuSettings::GetVersionString()
{
uint32_t version = GetVersion();
return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string(
version & 0xFF);
return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string(version & 0xFF);
}
void EmuSettings::ProcessString(string& str, const char** strPointer)
void EmuSettings::ProcessString(string & str, const char ** strPointer)
{
//Make a copy of the string and keep it (the original pointer will not be valid after the call is over)
if (*strPointer)
{
if(*strPointer) {
str = *strPointer;
}
else
{
} else {
str.clear();
}
*strPointer = str.c_str();
@ -74,16 +70,14 @@ AudioConfig EmuSettings::GetAudioConfig()
void EmuSettings::SetInputConfig(InputConfig config)
{
bool controllersChanged = false;
for (int i = 0; i < 5; i++)
{
for(int i = 0; i < 5; i++) {
controllersChanged |= _input.Controllers[i].Type != config.Controllers[i].Type;
}
_input = config;
_inputConfigVersion++;
if (controllersChanged)
{
if(controllersChanged) {
//Used by net play
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ConfigChanged);
}
@ -91,10 +85,8 @@ void EmuSettings::SetInputConfig(InputConfig config)
InputConfig EmuSettings::GetInputConfig()
{
if (CheckFlag(EmulationFlags::GameboyMode))
{
if (_input.Controllers[0].Type != ControllerType::SnesController)
{
if(CheckFlag(EmulationFlags::GameboyMode)) {
if(_input.Controllers[0].Type != ControllerType::SnesController) {
//Force SNES controller for P1 for gameboy-only mode
InputConfig input = _input;
input.Controllers[0].Type = ControllerType::SnesController;
@ -111,20 +103,14 @@ uint32_t EmuSettings::GetInputConfigVersion()
void EmuSettings::SetEmulationConfig(EmulationConfig config)
{
bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0 ||
_emulation.GsuClockSpeed > 100;
bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0 || config.
GsuClockSpeed > 100;
bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0 || _emulation.GsuClockSpeed > 100;
bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0 || config.GsuClockSpeed > 100;
_emulation = config;
if (prevOverclockEnabled != overclockEnabled)
{
if (overclockEnabled)
{
if(prevOverclockEnabled != overclockEnabled) {
if(overclockEnabled) {
MessageManager::DisplayMessage("Overclock", "OverclockEnabled");
}
else
{
} else {
MessageManager::DisplayMessage("Overclock", "OverclockDisabled");
}
@ -191,16 +177,11 @@ void EmuSettings::SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCo
{
_emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination;
for (int i = 0; i < 3; i++)
{
for (std::pair<const uint32_t, KeyCombination>& kvp : _emulatorKeys[i])
{
if (keyCombination.IsSubsetOf(kvp.second))
{
for(int i = 0; i < 3; i++) {
for(std::pair<const uint32_t, KeyCombination> &kvp : _emulatorKeys[i]) {
if(keyCombination.IsSubsetOf(kvp.second)) {
_shortcutSupersets[keySetIndex][(uint32_t)shortcut].push_back(kvp.second);
}
else if (kvp.second.IsSubsetOf(keyCombination))
{
} else if(kvp.second.IsSubsetOf(keyCombination)) {
_shortcutSupersets[i][kvp.first].push_back(keyCombination);
}
}
@ -211,14 +192,10 @@ void EmuSettings::SetShortcutKeys(vector<ShortcutKeyInfo> shortcuts)
{
ClearShortcutKeys();
for (ShortcutKeyInfo& shortcut : shortcuts)
{
if (_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty())
{
for(ShortcutKeyInfo &shortcut : shortcuts) {
if(_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty()) {
SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 0);
}
else
{
} else {
SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 1);
}
}
@ -227,8 +204,7 @@ void EmuSettings::SetShortcutKeys(vector<ShortcutKeyInfo> shortcuts)
KeyCombination EmuSettings::GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex)
{
auto result = _emulatorKeys[keySetIndex].find((int)shortcut);
if (result != _emulatorKeys[keySetIndex].end())
{
if(result != _emulatorKeys[keySetIndex].end()) {
return result->second;
}
return {};
@ -242,16 +218,13 @@ vector<KeyCombination> EmuSettings::GetShortcutSupersets(EmulatorShortcut shortc
OverscanDimensions EmuSettings::GetOverscan()
{
OverscanDimensions overscan;
if (CheckFlag(EmulationFlags::GameboyMode))
{
if(CheckFlag(EmulationFlags::GameboyMode)) {
//Force overscan values for gameboy-only mode (not SGB)
overscan.Left = 0;
overscan.Right = 256 - 160;
overscan.Top = 0;
overscan.Bottom = 239 - 144;
}
else
{
} else {
overscan.Left = _video.OverscanLeft;
overscan.Right = _video.OverscanRight;
overscan.Top = _video.OverscanTop;
@ -267,28 +240,20 @@ uint32_t EmuSettings::GetRewindBufferSize()
uint32_t EmuSettings::GetEmulationSpeed()
{
if (CheckFlag(EmulationFlags::MaximumSpeed))
{
if(CheckFlag(EmulationFlags::MaximumSpeed)) {
return 0;
}
else if (CheckFlag(EmulationFlags::Turbo))
{
} else if(CheckFlag(EmulationFlags::Turbo)) {
return _emulation.TurboSpeed;
}
else if (CheckFlag(EmulationFlags::Rewind))
{
} else if(CheckFlag(EmulationFlags::Rewind)) {
return _emulation.RewindSpeed;
}
else
{
} else {
return _emulation.EmulationSpeed;
}
}
double EmuSettings::GetAspectRatio(ConsoleRegion region)
{
switch (_video.AspectRatio)
{
switch(_video.AspectRatio) {
case VideoAspectRatio::NoStretching: return 0.0;
case VideoAspectRatio::Auto: return region == ConsoleRegion::Pal ? (11.0 / 8.0) : (8.0 / 7.0);
case VideoAspectRatio::NTSC: return 8.0 / 7.0;
@ -302,28 +267,23 @@ double EmuSettings::GetAspectRatio(ConsoleRegion region)
void EmuSettings::SetFlag(EmulationFlags flag)
{
if ((_flags & (int)flag) == 0)
{
if((_flags & (int)flag) == 0) {
_flags |= (int)flag;
}
}
void EmuSettings::SetFlagState(EmulationFlags flag, bool enabled)
{
if (enabled)
{
if(enabled) {
SetFlag(flag);
}
else
{
} else {
ClearFlag(flag);
}
}
void EmuSettings::ClearFlag(EmulationFlags flag)
{
if ((_flags & (int)flag) != 0)
{
if((_flags & (int)flag) != 0) {
_flags &= ~(int)flag;
}
}
@ -335,17 +295,12 @@ bool EmuSettings::CheckFlag(EmulationFlags flag)
void EmuSettings::SetDebuggerFlag(DebuggerFlags flag, bool enabled)
{
if (enabled)
{
if ((_debuggerFlags & (int)flag) == 0)
{
if(enabled) {
if((_debuggerFlags & (int)flag) == 0) {
_debuggerFlags |= (int)flag;
}
}
else
{
if ((_debuggerFlags & (int)flag) != 0)
{
} else {
if((_debuggerFlags & (int)flag) != 0) {
_debuggerFlags &= ~(int)flag;
}
}
@ -358,17 +313,13 @@ bool EmuSettings::CheckDebuggerFlag(DebuggerFlags flag)
void EmuSettings::InitializeRam(void* data, uint32_t length)
{
switch (_emulation.RamPowerOnState)
{
switch(_emulation.RamPowerOnState) {
default:
case RamState::AllZeros: memset(data, 0, length);
break;
case RamState::AllOnes: memset(data, 0xFF, length);
break;
case RamState::AllZeros: memset(data, 0, length); break;
case RamState::AllOnes: memset(data, 0xFF, length); break;
case RamState::Random:
std::uniform_int_distribution<> dist(0, 255);
for (uint32_t i = 0; i < length; i++)
{
for(uint32_t i = 0; i < length; i++) {
((uint8_t*)data)[i] = dist(_mt);
}
break;
@ -393,8 +344,7 @@ bool EmuSettings::IsInputEnabled()
double EmuSettings::GetControllerDeadzoneRatio()
{
switch (_input.ControllerDeadzoneSize)
{
switch(_input.ControllerDeadzoneSize) {
case 0: return 0.5;
case 1: return 0.75;
case 2: return 1;

View file

@ -31,7 +31,7 @@ private:
std::unordered_map<uint32_t, KeyCombination> _emulatorKeys[3];
std::unordered_map<uint32_t, vector<KeyCombination>> _shortcutSupersets[3];
void ProcessString(string& str, const char** strPointer);
void ProcessString(string &str, const char** strPointer);
void ClearShortcutKeys();
void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex);

View file

@ -10,8 +10,7 @@
#include "DefaultVideoFilter.h"
#include "BaseEventManager.h"
EventManager::EventManager(Debugger* debugger, Cpu* cpu, Ppu* ppu, MemoryManager* memoryManager,
DmaController* dmaController)
EventManager::EventManager(Debugger *debugger, Cpu *cpu, Ppu *ppu, MemoryManager *memoryManager, DmaController *dmaController)
{
_debugger = debugger;
_cpu = cpu;
@ -28,7 +27,7 @@ EventManager::~EventManager()
delete[] _ppuBuffer;
}
void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId)
void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo &operation, int32_t breakpointId)
{
DebugEventInfo evt = {};
evt.Type = type;
@ -37,13 +36,10 @@ void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation,
evt.Cycle = _memoryManager->GetHClock();
evt.BreakpointId = breakpointId;
if (operation.Type == MemoryOperationType::DmaRead || operation.Type == MemoryOperationType::DmaWrite)
{
if(operation.Type == MemoryOperationType::DmaRead || operation.Type == MemoryOperationType::DmaWrite) {
evt.DmaChannel = _dmaController->GetActiveChannel();
evt.DmaChannelInfo = _dmaController->GetChannelConfig(evt.DmaChannel & 0x07);
}
else
{
} else {
evt.DmaChannel = -1;
}
@ -68,7 +64,7 @@ void EventManager::AddEvent(DebugEventType type)
_debugEvents.push_back(evt);
}
void EventManager::GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount)
void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount)
{
auto lock = _lock.AcquireSafe();
uint32_t eventCount = std::min(maxEventCount, (uint32_t)_sentEvents.size());
@ -76,14 +72,12 @@ void EventManager::GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount
maxEventCount = eventCount;
}
DebugEventInfo EventManager::GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options)
DebugEventInfo EventManager::GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options)
{
auto lock = _lock.AcquireSafe();
for (DebugEventInfo& evt : _sentEvents)
{
if (evt.Cycle == cycle && evt.Scanline == scanline)
{
for(DebugEventInfo &evt : _sentEvents) {
if(evt.Cycle == cycle && evt.Scanline == scanline) {
return evt;
}
}
@ -106,191 +100,120 @@ void EventManager::ClearFrameEvents()
_debugEvents.clear();
}
void EventManager::FilterEvents(EventViewerDisplayOptions& options)
void EventManager::FilterEvents(EventViewerDisplayOptions &options)
{
auto lock = _lock.AcquireSafe();
_sentEvents.clear();
vector<DebugEventInfo> events = _snapshot;
if (options.ShowPreviousFrameEvents && _snapshotScanline != 0)
{
if(options.ShowPreviousFrameEvents && _snapshotScanline != 0) {
uint32_t key = (_snapshotScanline << 16) + _snapshotCycle;
for (DebugEventInfo& evt : _prevDebugEvents)
{
for(DebugEventInfo &evt : _prevDebugEvents) {
uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle;
if (evtKey > key)
{
if(evtKey > key) {
events.push_back(evt);
}
}
}
for (DebugEventInfo& evt : events)
{
bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type ==
MemoryOperationType::DmaWrite;
bool isDma = evt.Operation.Type == MemoryOperationType::DmaWrite || evt.Operation.Type ==
MemoryOperationType::DmaRead;
for(DebugEventInfo &evt : events) {
bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite;
bool isDma = evt.Operation.Type == MemoryOperationType::DmaWrite || evt.Operation.Type == MemoryOperationType::DmaRead;
bool showEvent = false;
switch (evt.Type)
{
case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints;
break;
case DebugEventType::Irq: showEvent = options.ShowIrq;
break;
case DebugEventType::Nmi: showEvent = options.ShowNmi;
break;
switch(evt.Type) {
case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints;break;
case DebugEventType::Irq: showEvent = options.ShowIrq; break;
case DebugEventType::Nmi: showEvent = options.ShowNmi; break;
case DebugEventType::Register:
if (isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07])
{
if(isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07]) {
showEvent = false;
break;
}
uint16_t reg = evt.Operation.Address & 0xFFFF;
if (reg <= 0x213F)
{
if (isWrite)
{
if (reg >= 0x2101 && reg <= 0x2104)
{
if(reg <= 0x213F) {
if(isWrite) {
if(reg >= 0x2101 && reg <= 0x2104) {
showEvent = options.ShowPpuRegisterOamWrites;
}
else if (reg >= 0x2105 && reg <= 0x210C)
{
} else if(reg >= 0x2105 && reg <= 0x210C) {
showEvent = options.ShowPpuRegisterBgOptionWrites;
}
else if (reg >= 0x210D && reg <= 0x2114)
{
} else if(reg >= 0x210D && reg <= 0x2114) {
showEvent = options.ShowPpuRegisterBgScrollWrites;
}
else if (reg >= 0x2115 && reg <= 0x2119)
{
} else if(reg >= 0x2115 && reg <= 0x2119) {
showEvent = options.ShowPpuRegisterVramWrites;
}
else if (reg >= 0x211A && reg <= 0x2120)
{
} else if(reg >= 0x211A && reg <= 0x2120) {
showEvent = options.ShowPpuRegisterMode7Writes;
}
else if (reg >= 0x2121 && reg <= 0x2122)
{
} else if(reg >= 0x2121 && reg <= 0x2122) {
showEvent = options.ShowPpuRegisterCgramWrites;
}
else if (reg >= 0x2123 && reg <= 0x212B)
{
} else if(reg >= 0x2123 && reg <= 0x212B) {
showEvent = options.ShowPpuRegisterWindowWrites;
}
else
{
} else {
showEvent = options.ShowPpuRegisterOtherWrites;
}
}
else
{
} else {
showEvent = options.ShowPpuRegisterReads;
}
}
else if (reg <= 0x217F)
{
} else if(reg <= 0x217F) {
showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads;
}
else if (reg <= 0x2183)
{
} else if(reg <= 0x2183) {
showEvent = isWrite ? options.ShowWorkRamRegisterWrites : options.ShowWorkRamRegisterReads;
}
else if (reg >= 0x4000)
{
} else if(reg >= 0x4000) {
showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads;
}
break;
}
if (showEvent)
{
if(showEvent) {
_sentEvents.push_back(evt);
}
}
}
void EventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer,
EventViewerDisplayOptions& options)
void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options)
{
bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type ==
MemoryOperationType::DmaWrite;
bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite;
uint32_t color = 0;
switch (evt.Type)
{
case DebugEventType::Breakpoint: color = options.BreakpointColor;
break;
case DebugEventType::Irq: color = options.IrqColor;
break;
case DebugEventType::Nmi: color = options.NmiColor;
break;
switch(evt.Type) {
case DebugEventType::Breakpoint: color = options.BreakpointColor; break;
case DebugEventType::Irq: color = options.IrqColor; break;
case DebugEventType::Nmi: color = options.NmiColor; break;
case DebugEventType::Register:
uint16_t reg = evt.Operation.Address & 0xFFFF;
if (reg <= 0x213F)
{
if (isWrite)
{
if (reg >= 0x2101 && reg <= 0x2104)
{
if(reg <= 0x213F) {
if(isWrite) {
if(reg >= 0x2101 && reg <= 0x2104) {
color = options.PpuRegisterWriteOamColor;
}
else if (reg >= 0x2105 && reg <= 0x210C)
{
} else if(reg >= 0x2105 && reg <= 0x210C) {
color = options.PpuRegisterWriteBgOptionColor;
}
else if (reg >= 0x210D && reg <= 0x2114)
{
} else if(reg >= 0x210D && reg <= 0x2114) {
color = options.PpuRegisterWriteBgScrollColor;
}
else if (reg >= 0x2115 && reg <= 0x2119)
{
} else if(reg >= 0x2115 && reg <= 0x2119) {
color = options.PpuRegisterWriteVramColor;
}
else if (reg >= 0x211A && reg <= 0x2120)
{
} else if(reg >= 0x211A && reg <= 0x2120) {
color = options.PpuRegisterWriteMode7Color;
}
else if (reg >= 0x2121 && reg <= 0x2122)
{
} else if(reg >= 0x2121 && reg <= 0x2122) {
color = options.PpuRegisterWriteCgramColor;
}
else if (reg >= 0x2123 && reg <= 0x212B)
{
} else if(reg >= 0x2123 && reg <= 0x212B) {
color = options.PpuRegisterWriteWindowColor;
}
else
{
} else {
color = options.PpuRegisterWriteOtherColor;
}
}
else
{
} else {
color = options.PpuRegisterReadColor;
}
}
else if (reg <= 0x217F)
{
} else if(reg <= 0x217F) {
color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor;
}
else if (reg <= 0x2183)
{
} else if(reg <= 0x2183) {
color = isWrite ? options.WorkRamRegisterWriteColor : options.WorkRamRegisterReadColor;
}
else if (reg >= 0x4000)
{
} else if(reg >= 0x4000) {
color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor;
}
break;
}
if (drawBackground)
{
if(drawBackground){
color = 0xFF000000 | ((color >> 1) & 0x7F7F7F);
}
else
{
} else {
color |= 0xFF000000;
}
@ -301,13 +224,10 @@ void EventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t*
uint32_t y = std::min<uint32_t>(evt.Scanline * 2, _scanlineCount * 2);
uint32_t x = evt.Cycle / 2;
for (int i = iMin; i <= iMax; i++)
{
for (int j = jMin; j <= jMax; j++)
{
for(int i = iMin; i <= iMax; i++) {
for(int j = jMin; j <= jMax; j++) {
int32_t pos = (y + i) * EventManager::ScanlineWidth + x + j;
if (pos < 0 || pos >= EventManager::ScanlineWidth * (int)_scanlineCount * 2)
{
if(pos < 0 || pos >= EventManager::ScanlineWidth * (int)_scanlineCount * 2) {
continue;
}
buffer[pos] = color;
@ -327,17 +247,14 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
_overscanMode = _ppu->GetState().OverscanMode;
_useHighResOutput = _ppu->IsHighResOutput();
if (scanline >= _ppu->GetNmiScanline() || scanline == 0)
{
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256 * 239)) * sizeof(uint16_t));
}
else
{
if(scanline >= _ppu->GetNmiScanline() || scanline == 0) {
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256*239)) * sizeof(uint16_t));
} else {
uint16_t adjustedScanline = scanline + (_overscanMode ? 0 : 7);
uint32_t size = _useHighResOutput ? (512 * 478) : (256 * 239);
uint32_t offset = _useHighResOutput ? (512 * adjustedScanline * 2) : (256 * adjustedScanline);
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), offset * sizeof(uint16_t));
memcpy(_ppuBuffer + offset, _ppu->GetPreviousScreenBuffer() + offset, (size - offset) * sizeof(uint16_t));
memcpy(_ppuBuffer+offset, _ppu->GetPreviousScreenBuffer()+offset, (size - offset) * sizeof(uint16_t));
}
_snapshot = _debugEvents;
@ -347,29 +264,25 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
return _scanlineCount;
}
void EventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options)
void EventManager::GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options)
{
auto lock = _lock.AcquireSafe();
if (_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4)
{
if(_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4) {
return;
}
for (int i = 0; i < EventManager::ScanlineWidth * (int)_scanlineCount * 2; i++)
{
for(int i = 0; i < EventManager::ScanlineWidth * (int)_scanlineCount * 2; i++) {
buffer[i] = 0xFF555555;
}
//Skip the first 7 blank lines in the buffer when overscan mode is off
uint16_t* src = _ppuBuffer + (_overscanMode ? 0 : (_useHighResOutput ? (512 * 14) : (256 * 7)));
uint16_t *src = _ppuBuffer + (_overscanMode ? 0 : (_useHighResOutput ? (512 * 14) : (256 * 7)));
for (uint32_t y = 0, len = _overscanMode ? 239 * 2 : 224 * 2; y < len; y++)
{
for (uint32_t x = 0; x < 512; x++)
{
for(uint32_t y = 0, len = _overscanMode ? 239*2 : 224*2; y < len; y++) {
for(uint32_t x = 0; x < 512; x++) {
int srcOffset = _useHighResOutput ? ((y << 9) | x) : (((y >> 1) << 8) | (x >> 1));
buffer[(y + 2) * EventManager::ScanlineWidth + x + 22 * 2] = DefaultVideoFilter::ToArgb(src[srcOffset]);
buffer[(y + 2)*EventManager::ScanlineWidth + x + 22*2] = DefaultVideoFilter::ToArgb(src[srcOffset]);
}
}
@ -377,24 +290,20 @@ void EventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, Event
constexpr uint32_t currentScanlineColor = 0xFFFFFF55;
int nmiScanline = (_overscanMode ? 240 : 225) * 2 * EventManager::ScanlineWidth;
uint32_t scanlineOffset = _snapshotScanline * 2 * EventManager::ScanlineWidth;
for (int i = 0; i < EventManager::ScanlineWidth; i++)
{
for(int i = 0; i < EventManager::ScanlineWidth; i++) {
buffer[nmiScanline + i] = nmiColor;
buffer[nmiScanline + EventManager::ScanlineWidth + i] = nmiColor;
if (_snapshotScanline != 0)
{
if(_snapshotScanline != 0) {
buffer[scanlineOffset + i] = currentScanlineColor;
buffer[scanlineOffset + EventManager::ScanlineWidth + i] = currentScanlineColor;
}
}
FilterEvents(options);
for (DebugEventInfo& evt : _sentEvents)
{
for(DebugEventInfo &evt : _sentEvents) {
DrawEvent(evt, true, buffer, options);
}
for (DebugEventInfo& evt : _sentEvents)
{
for(DebugEventInfo &evt : _sentEvents) {
DrawEvent(evt, false, buffer, options);
}
}

View file

@ -19,11 +19,11 @@ class EventManager final : public IEventManager
private:
static constexpr int ScanlineWidth = 1364 / 2;
Cpu* _cpu;
Ppu* _ppu;
Cpu * _cpu;
Ppu *_ppu;
MemoryManager* _memoryManager;
DmaController* _dmaController;
Debugger* _debugger;
DmaController *_dmaController;
Debugger *_debugger;
vector<DebugEventInfo> _debugEvents;
vector<DebugEventInfo> _prevDebugEvents;
vector<DebugEventInfo> _sentEvents;
@ -36,23 +36,23 @@ private:
bool _overscanMode = false;
bool _useHighResOutput = false;
uint32_t _scanlineCount = 262;
uint16_t* _ppuBuffer = nullptr;
uint16_t *_ppuBuffer = nullptr;
void DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options);
void FilterEvents(EventViewerDisplayOptions& options);
void DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options);
void FilterEvents(EventViewerDisplayOptions &options);
public:
EventManager(Debugger* debugger, Cpu* cpu, Ppu* ppu, MemoryManager* memoryManager, DmaController* dmaController);
EventManager(Debugger *debugger, Cpu *cpu, Ppu *ppu, MemoryManager *memoryManager, DmaController *dmaController);
~EventManager();
void AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId = -1);
void AddEvent(DebugEventType type, MemoryOperationInfo &operation, int32_t breakpointId = -1);
void AddEvent(DebugEventType type);
void GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount);
void GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount);
uint32_t GetEventCount(EventViewerDisplayOptions options);
void ClearFrameEvents();
uint32_t TakeEventSnapshot(EventViewerDisplayOptions options);
void GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options);
DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options);
void GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options);
DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options);
};

File diff suppressed because it is too large Load diff

View file

@ -39,10 +39,8 @@ enum EvalOperators : int64_t
LogicalNot = 20000000053,
//Used to read ram address
Bracket = 20000000054,
//Read byte
Braces = 20000000055,
//Read word
Bracket = 20000000054, //Read byte
Braces = 20000000055, //Read word
//Special value, not used as an operator
Parenthesis = 20000000100,
@ -166,29 +164,25 @@ private:
CpuType _cpuType;
SnesMemoryType _cpuMemory;
bool IsOperator(string token, int& precedence, bool unaryOperator);
bool IsOperator(string token, int &precedence, bool unaryOperator);
EvalOperators GetOperator(string token, bool unaryOperator);
bool CheckSpecialTokens(string expression, size_t& pos, string& output, ExpressionData& data);
bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data);
int64_t ProcessCpuSpcTokens(string token, bool spc);
int64_t ProcessSharedTokens(string token);
int64_t ProcessGsuTokens(string token);
int64_t ProcessGameboyTokens(string token);
string GetNextToken(string expression, size_t& pos, ExpressionData& data, bool& success, bool previousTokenIsOp);
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators>& opStack,
std::stack<int>& precedenceStack, vector<int64_t>& outputQueue);
bool ToRpn(string expression, ExpressionData& data);
int32_t PrivateEvaluate(string expression, DebugState& state, EvalResultType& resultType,
MemoryOperationInfo& operationInfo, bool& success);
string GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp);
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int64_t> &outputQueue);
bool ToRpn(string expression, ExpressionData &data);
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo, bool &success);
ExpressionData* PrivateGetRpnList(string expression, bool& success);
public:
ExpressionEvaluator(Debugger* debugger, CpuType cpuType);
int32_t Evaluate(ExpressionData& data, DebugState& state, EvalResultType& resultType,
MemoryOperationInfo& operationInfo);
int32_t Evaluate(string expression, DebugState& state, EvalResultType& resultType,
MemoryOperationInfo& operationInfo);
ExpressionData GetRpnList(string expression, bool& success);
int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo);
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo);
ExpressionData GetRpnList(string expression, bool &success);
bool Validate(string expression);

View file

@ -14,29 +14,20 @@ struct MissingFirmwareMessage
class FirmwareHelper
{
private:
static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData,
vector<uint8_t>& programRom, vector<uint8_t>& dataRom, uint32_t programSize,
uint32_t dataSize)
{
VirtualFile combinedFirmware(
FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename));
if (combinedFirmware.GetSize() == programSize + dataSize)
static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector<uint8_t> &programRom, vector<uint8_t> &dataRom, uint32_t programSize, uint32_t dataSize)
{
VirtualFile combinedFirmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename));
if(combinedFirmware.GetSize() == programSize + dataSize) {
vector<uint8_t> firmwareData;
combinedFirmware.ReadFile(firmwareData);
programRom.insert(programRom.end(), firmwareData.begin(), firmwareData.begin() + programSize);
dataRom.insert(dataRom.end(), firmwareData.begin() + programSize, firmwareData.end());
return true;
}
else
{
VirtualFile splitFirmwareProg(
FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameProgram));
VirtualFile splitFirmwareData(
FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameData));
} else {
VirtualFile splitFirmwareProg(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameProgram));
VirtualFile splitFirmwareData(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameData));
if (splitFirmwareProg.GetSize() == programSize && splitFirmwareData.GetSize() == dataSize)
{
if(splitFirmwareProg.GetSize() == programSize && splitFirmwareData.GetSize() == dataSize) {
splitFirmwareProg.ReadFile(programRom);
splitFirmwareData.ReadFile(dataRom);
return true;
@ -48,8 +39,7 @@ private:
static bool AttemptLoadBsxFirmware(uint8_t** prgRom, uint32_t& prgSize)
{
VirtualFile firmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), "BS-X.bin"));
if (firmware.IsValid() && firmware.GetSize() >= 0x8000)
{
if(firmware.IsValid() && firmware.GetSize() >= 0x8000) {
*prgRom = new uint8_t[firmware.GetSize()];
prgSize = (uint32_t)firmware.GetSize();
firmware.ReadFile(*prgRom, (uint32_t)firmware.GetSize());
@ -63,14 +53,12 @@ private:
{
string path = FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), filename);
VirtualFile firmware(path);
if ((!firmware.IsValid() || firmware.GetSize() != size) && !altFilename.empty())
{
if((!firmware.IsValid() || firmware.GetSize() != size) && !altFilename.empty()) {
string altPath = FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), altFilename);
firmware = VirtualFile(altPath);
}
if (firmware.IsValid() && firmware.GetSize() == size)
{
if(firmware.IsValid() && firmware.GetSize() == size) {
*out = new uint8_t[firmware.GetSize()];
firmware.ReadFile(*out, (uint32_t)firmware.GetSize());
return true;
@ -80,20 +68,13 @@ private:
}
public:
static bool LoadDspFirmware(Console* console, FirmwareType type, string combinedFilename,
string splitFilenameProgram, string splitFilenameData, vector<uint8_t>& programRom,
vector<uint8_t>& dataRom, vector<uint8_t>& embeddedFirware,
uint32_t programSize = 0x1800, uint32_t dataSize = 0x800)
{
if (embeddedFirware.size() == programSize + dataSize)
static bool LoadDspFirmware(Console *console, FirmwareType type, string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector<uint8_t> &programRom, vector<uint8_t> &dataRom, vector<uint8_t> &embeddedFirware, uint32_t programSize = 0x1800, uint32_t dataSize = 0x800)
{
if(embeddedFirware.size() == programSize + dataSize) {
programRom.insert(programRom.end(), embeddedFirware.begin(), embeddedFirware.begin() + programSize);
dataRom.insert(dataRom.end(), embeddedFirware.begin() + programSize, embeddedFirware.end());
return true;
}
else if (AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom,
programSize, dataSize))
{
} else if(AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, programSize, dataSize)) {
return true;
}
@ -104,9 +85,7 @@ public:
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
//Try again in case the user selected a valid firmware file
if (AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom,
programSize, dataSize))
{
if(AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, programSize, dataSize)) {
return true;
}
@ -116,19 +95,17 @@ public:
static bool LoadBsxFirmware(Console* console, uint8_t** prgRom, uint32_t& prgSize)
{
if (AttemptLoadBsxFirmware(prgRom, prgSize))
{
if(AttemptLoadBsxFirmware(prgRom, prgSize)) {
return true;
}
MissingFirmwareMessage msg;
msg.Filename = "BS-X.bin";
msg.Firmware = FirmwareType::Satellaview;
msg.Size = 1024 * 1024;
msg.Size = 1024*1024;
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
if (AttemptLoadBsxFirmware(prgRom, prgSize))
{
if(AttemptLoadBsxFirmware(prgRom, prgSize)) {
return true;
}
@ -140,8 +117,7 @@ public:
{
string filename = useSgb2 ? "SGB2.sfc" : "SGB1.sfc";
prgSize = useSgb2 ? 0x80000 : 0x40000;
if (AttemptLoadFirmware(prgRom, filename, prgSize))
{
if(AttemptLoadFirmware(prgRom, filename, prgSize)) {
return true;
}
@ -151,8 +127,7 @@ public:
msg.Size = prgSize;
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
if (AttemptLoadFirmware(prgRom, filename, prgSize))
{
if(AttemptLoadFirmware(prgRom, filename, prgSize)) {
return true;
}
@ -164,26 +139,16 @@ public:
{
string filename;
string altFilename;
switch (type)
{
switch(type) {
default:
case FirmwareType::Gameboy: filename = "dmg_boot.bin";
altFilename = "gb_bios.bin";
break;
case FirmwareType::GameboyColor: filename = "cgb_boot.bin";
altFilename = "gbc_bios.bin";
break;
case FirmwareType::Sgb1GameboyCpu: filename = "sgb_boot.bin";
altFilename = "sgb_bios.bin";
break;
case FirmwareType::Sgb2GameboyCpu: filename = "sgb2_boot.bin";
altFilename = "sgb_bios.bin";
break;
case FirmwareType::Gameboy: filename = "dmg_boot.bin"; altFilename = "gb_bios.bin"; break;
case FirmwareType::GameboyColor: filename = "cgb_boot.bin"; altFilename = "gbc_bios.bin"; break;
case FirmwareType::Sgb1GameboyCpu: filename = "sgb_boot.bin"; altFilename = "sgb_bios.bin"; break;
case FirmwareType::Sgb2GameboyCpu: filename = "sgb2_boot.bin"; altFilename = "sgb_bios.bin"; break;
}
uint32_t size = type == FirmwareType::GameboyColor ? 2304 : 256;
if (AttemptLoadFirmware(bootRom, filename, size, altFilename))
{
if(AttemptLoadFirmware(bootRom, filename, size, altFilename)) {
return true;
}

View file

@ -11,15 +11,13 @@ private:
string _disconnectMessage;
protected:
void Serialize(Serializer& s) override
void Serialize(Serializer &s) override
{
s.Stream(_disconnectMessage);
}
public:
ForceDisconnectMessage(void* buffer, uint32_t length) : NetMessage(buffer, length)
{
}
ForceDisconnectMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
ForceDisconnectMessage(string message) : NetMessage(MessageType::ForceDisconnect)
{

View file

@ -25,8 +25,7 @@ public:
void ProcessFrame()
{
if (_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300)
{
if(_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300) {
//Reset the timers, this can happen in 3 scenarios:
//1) Target frame rate changed
//2) The console was reset/power cycled or the emulation was paused (with or without the debugger)
@ -42,8 +41,7 @@ public:
bool WaitForNextFrame()
{
if (_targetTime - _clockTimer.GetElapsedMS() > 50)
{
if(_targetTime - _clockTimer.GetElapsedMS() > 50) {
//When sleeping for a long time (e.g <= 25% speed), sleep in small chunks and check to see if we need to stop sleeping between each sleep call
_clockTimer.WaitUntil(_clockTimer.GetElapsedMS() + 40);
return true;

View file

@ -21,8 +21,7 @@ GameClient::GameClient(shared_ptr<Console> console)
GameClient::~GameClient()
{
_stop = true;
if (_clientThread)
{
if(_clientThread) {
_clientThread->join();
}
}
@ -33,14 +32,13 @@ bool GameClient::Connected()
return instance ? instance->_connected : false;
}
void GameClient::Connect(shared_ptr<Console> console, ClientConnectionData& connectionData)
void GameClient::Connect(shared_ptr<Console> console, ClientConnectionData &connectionData)
{
_instance.reset(new GameClient(console));
console->GetNotificationManager()->RegisterNotificationListener(_instance);
shared_ptr<GameClient> instance = _instance;
if (instance)
{
if(instance) {
instance->PrivateConnect(connectionData);
instance->_clientThread.reset(new thread(&GameClient::Exec, instance.get()));
}
@ -57,18 +55,15 @@ shared_ptr<GameClientConnection> GameClient::GetConnection()
return instance ? instance->_connection : nullptr;
}
void GameClient::PrivateConnect(ClientConnectionData& connectionData)
void GameClient::PrivateConnect(ClientConnectionData &connectionData)
{
_stop = false;
shared_ptr<Socket> socket(new Socket());
if (socket->Connect(connectionData.Host.c_str(), connectionData.Port))
{
if(socket->Connect(connectionData.Host.c_str(), connectionData.Port)) {
_connection.reset(new GameClientConnection(_console, socket, connectionData));
_console->GetNotificationManager()->RegisterNotificationListener(_connection);
_connected = true;
}
else
{
} else {
MessageManager::DisplayMessage("NetPlay", "CouldNotConnect");
_connected = false;
}
@ -76,17 +71,12 @@ void GameClient::PrivateConnect(ClientConnectionData& connectionData)
void GameClient::Exec()
{
if (_connected)
{
while (!_stop)
{
if (!_connection->ConnectionError())
{
if(_connected) {
while(!_stop) {
if(!_connection->ConnectionError()) {
_connection->ProcessMessages();
_connection->SendInput();
}
else
{
} else {
_connected = false;
_connection->Shutdown();
_connection.reset();
@ -99,11 +89,10 @@ void GameClient::Exec()
void GameClient::ProcessNotification(ConsoleNotificationType type, void* parameter)
{
if (type == ConsoleNotificationType::GameLoaded &&
if(type == ConsoleNotificationType::GameLoaded &&
std::this_thread::get_id() != _clientThread->get_id() &&
std::this_thread::get_id() != _console->GetEmulationThreadId()
)
{
) {
//Disconnect if the client tried to manually load a game
//A deadlock occurs if this is called from the emulation thread while a network message is being processed
GameClient::Disconnect();
@ -113,8 +102,7 @@ void GameClient::ProcessNotification(ConsoleNotificationType type, void* paramet
void GameClient::SelectController(uint8_t port)
{
shared_ptr<GameClientConnection> connection = GetConnection();
if (connection)
{
if(connection) {
connection->SelectController(port);
}
}

View file

@ -23,7 +23,7 @@ private:
static shared_ptr<GameClientConnection> GetConnection();
void PrivateConnect(ClientConnectionData& connectionData);
void PrivateConnect(ClientConnectionData &connectionData);
void Exec();
public:
@ -31,7 +31,7 @@ public:
virtual ~GameClient();
static bool Connected();
static void Connect(shared_ptr<Console> console, ClientConnectionData& connectionData);
static void Connect(shared_ptr<Console> console, ClientConnectionData &connectionData);
static void Disconnect();
static void SelectController(uint8_t port);

View file

@ -17,8 +17,7 @@
#include "NotificationManager.h"
#include "RomFinder.h"
GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket,
ClientConnectionData& connectionData) : GameConnection(console, socket)
GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData &connectionData) : GameConnection(console, socket)
{
_connectionData = connectionData;
_shutdown = false;
@ -35,14 +34,12 @@ GameClientConnection::~GameClientConnection()
void GameClientConnection::Shutdown()
{
if (!_shutdown)
{
if(!_shutdown) {
_shutdown = true;
DisableControllers();
shared_ptr<ControlManager> controlManager = _console->GetControlManager();
if (controlManager)
{
if(controlManager) {
controlManager->UnregisterInputProvider(this);
}
@ -53,9 +50,7 @@ void GameClientConnection::Shutdown()
void GameClientConnection::SendHandshake()
{
HandShakeMessage message(_connectionData.PlayerName,
HandShakeMessage::GetPasswordHash(_connectionData.Password, _serverSalt),
_connectionData.Spectator, _console->GetSettings()->GetVersion());
HandShakeMessage message(_connectionData.PlayerName, HandShakeMessage::GetPasswordHash(_connectionData.Password, _serverSalt), _connectionData.Spectator, _console->GetSettings()->GetVersion());
SendNetMessage(message);
}
@ -68,8 +63,7 @@ void GameClientConnection::SendControllerSelection(uint8_t port)
void GameClientConnection::ClearInputData()
{
LockHandler lock = _writeLock.AcquireSafe();
for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
for(int i = 0; i < BaseControlDevice::PortCount; i++) {
_inputSize[i] = 0;
_inputData[i].clear();
}
@ -79,16 +73,14 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
{
GameInformationMessage* gameInfo;
switch (message->GetType())
{
switch(message->GetType()) {
case MessageType::ServerInformation:
_serverSalt = ((ServerInformationMessage*)message)->GetHashSalt();
SendHandshake();
break;
case MessageType::SaveState:
if (_gameLoaded)
{
if(_gameLoaded) {
DisableControllers();
_console->Lock();
ClearInputData();
@ -100,10 +92,8 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
break;
case MessageType::MovieData:
if (_gameLoaded)
{
PushControllerState(((MovieDataMessage*)message)->GetPortNumber(),
((MovieDataMessage*)message)->GetInputState());
if(_gameLoaded) {
PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), ((MovieDataMessage*)message)->GetInputState());
}
break;
@ -119,16 +109,12 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
DisableControllers();
_console->Lock();
gameInfo = (GameInformationMessage*)message;
if (gameInfo->GetPort() != _controllerPort)
{
if(gameInfo->GetPort() != _controllerPort) {
_controllerPort = gameInfo->GetPort();
if (_controllerPort == GameConnection::SpectatorPort)
{
if(_controllerPort == GameConnection::SpectatorPort) {
MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator");
}
else
{
} else {
MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1));
}
}
@ -137,20 +123,14 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
_console->Unlock();
_gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash());
if (!_gameLoaded)
{
if(!_gameLoaded) {
_console->Stop(true);
}
else
{
} else {
_console->GetControlManager()->UnregisterInputProvider(this);
_console->GetControlManager()->RegisterInputProvider(this);
if (gameInfo->IsPaused())
{
if(gameInfo->IsPaused()) {
_console->Pause();
}
else
{
} else {
_console->Resume();
}
}
@ -162,15 +142,11 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
bool GameClientConnection::AttemptLoadGame(string filename, string sha1Hash)
{
if (filename.size() > 0)
{
if (!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash))
{
if(filename.size() > 0) {
if(!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash)) {
MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom", filename);
return false;
}
else
{
} else {
return true;
}
}
@ -183,8 +159,7 @@ void GameClientConnection::PushControllerState(uint8_t port, ControlDeviceState
_inputData[port].push_back(state);
_inputSize[port]++;
if (_inputData[port].size() >= _minimumQueueSize)
{
if(_inputData[port].size() >= _minimumQueueSize) {
_waitForInput[port].Signal();
}
}
@ -194,36 +169,30 @@ void GameClientConnection::DisableControllers()
//Used to prevent deadlocks when client is trying to fill its buffer while the host changes the current game/settings/etc. (i.e situations where we need to call Console::Pause())
_enableControllers = false;
ClearInputData();
for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
for(int i = 0; i < BaseControlDevice::PortCount; i++) {
_waitForInput[i].Signal();
}
}
bool GameClientConnection::SetInput(BaseControlDevice* device)
bool GameClientConnection::SetInput(BaseControlDevice *device)
{
if (_enableControllers)
{
if(_enableControllers) {
uint8_t port = device->GetPort();
while (_inputSize[port] == 0)
{
while(_inputSize[port] == 0) {
_waitForInput[port].Wait();
if (port == 0 && _minimumQueueSize < 10)
{
if(port == 0 && _minimumQueueSize < 10) {
//Increase buffer size - reduces freezes at the cost of additional lag
_minimumQueueSize++;
}
if (_shutdown || !_enableControllers)
{
if(_shutdown || !_enableControllers) {
return true;
}
}
LockHandler lock = _writeLock.AcquireSafe();
if (_shutdown || !_enableControllers || _inputSize[port] == 0)
{
if(_shutdown || !_enableControllers || _inputSize[port] == 0) {
return true;
}
@ -231,13 +200,10 @@ bool GameClientConnection::SetInput(BaseControlDevice* device)
_inputData[port].pop_front();
_inputSize[port]--;
if (_inputData[port].size() > _minimumQueueSize)
{
if(_inputData[port].size() > _minimumQueueSize) {
//Too much data, catch up
_console->GetSettings()->SetFlag(EmulationFlags::MaximumSpeed);
}
else
{
} else {
_console->GetSettings()->ClearFlag(EmulationFlags::MaximumSpeed);
}
@ -249,41 +215,33 @@ bool GameClientConnection::SetInput(BaseControlDevice* device)
void GameClientConnection::InitControlDevice()
{
//Pretend we are using port 0 (to use player 1's keybindings during netplay)
_newControlDevice = ControlManager::CreateControllerDevice(
_console->GetSettings()->GetInputConfig().Controllers[_controllerPort].Type, 0, _console.get());
_newControlDevice = ControlManager::CreateControllerDevice(_console->GetSettings()->GetInputConfig().Controllers[_controllerPort].Type, 0, _console.get());
}
void GameClientConnection::ProcessNotification(ConsoleNotificationType type, void* parameter)
{
if (type == ConsoleNotificationType::ConfigChanged)
{
if(type == ConsoleNotificationType::ConfigChanged) {
InitControlDevice();
}
else if (type == ConsoleNotificationType::GameLoaded)
{
} else if(type == ConsoleNotificationType::GameLoaded) {
_console->GetControlManager()->RegisterInputProvider(this);
}
}
void GameClientConnection::SendInput()
{
if (_gameLoaded)
{
if (_newControlDevice)
{
if(_gameLoaded) {
if(_newControlDevice) {
_controlDevice = _newControlDevice;
_newControlDevice.reset();
}
ControlDeviceState inputState;
if (_controlDevice)
{
if(_controlDevice) {
_controlDevice->SetStateFromInput();
inputState = _controlDevice->GetRawState();
}
if (_lastInputSent != inputState)
{
if(_lastInputSent != inputState) {
InputDataMessage message(inputState);
SendNetMessage(message);
_lastInputSent = inputState;
@ -299,10 +257,8 @@ void GameClientConnection::SelectController(uint8_t port)
uint8_t GameClientConnection::GetAvailableControllers()
{
uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1;
for (PlayerInfo& playerInfo : _playerList)
{
if (playerInfo.ControllerPort < BaseControlDevice::PortCount)
{
for(PlayerInfo &playerInfo : _playerList) {
if(playerInfo.ControllerPort < BaseControlDevice::PortCount) {
availablePorts &= ~(1 << playerInfo.ControllerPort);
}
}

View file

@ -45,14 +45,14 @@ protected:
void ProcessMessage(NetMessage* message) override;
public:
GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData& connectionData);
GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData &connectionData);
virtual ~GameClientConnection();
void Shutdown();
void ProcessNotification(ConsoleNotificationType type, void* parameter) override;
bool SetInput(BaseControlDevice* device) override;
bool SetInput(BaseControlDevice *device) override;
void InitControlDevice();
void SendInput();

View file

@ -20,20 +20,17 @@ GameConnection::GameConnection(shared_ptr<Console> console, shared_ptr<Socket> s
void GameConnection::ReadSocket()
{
auto lock = _socketLock.AcquireSafe();
int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition,
0);
if (bytesReceived > 0)
{
int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition, 0);
if(bytesReceived > 0) {
_readPosition += bytesReceived;
}
}
bool GameConnection::ExtractMessage(void* buffer, uint32_t& messageLength)
bool GameConnection::ExtractMessage(void *buffer, uint32_t &messageLength)
{
messageLength = _readBuffer[0] | (_readBuffer[1] << 8) | (_readBuffer[2] << 16) | (_readBuffer[3] << 24);
if (messageLength > GameConnection::MaxMsgLength)
{
if(messageLength > GameConnection::MaxMsgLength) {
MessageManager::Log("[Netplay] Invalid data received, closing connection.");
Disconnect();
return false;
@ -41,9 +38,8 @@ bool GameConnection::ExtractMessage(void* buffer, uint32_t& messageLength)
int packetLength = messageLength + sizeof(messageLength);
if (_readPosition >= packetLength)
{
memcpy(buffer, _readBuffer + sizeof(messageLength), messageLength);
if(_readPosition >= packetLength) {
memcpy(buffer, _readBuffer+sizeof(messageLength), messageLength);
memmove(_readBuffer, _readBuffer + packetLength, _readPosition - packetLength);
_readPosition -= packetLength;
return true;
@ -55,13 +51,10 @@ NetMessage* GameConnection::ReadMessage()
{
ReadSocket();
if (_readPosition > 4)
{
if(_readPosition > 4) {
uint32_t messageLength;
if (ExtractMessage(_messageBuffer, messageLength))
{
switch ((MessageType)_messageBuffer[0])
{
if(ExtractMessage(_messageBuffer, messageLength)) {
switch((MessageType)_messageBuffer[0]) {
case MessageType::HandShake: return new HandShakeMessage(_messageBuffer, messageLength);
case MessageType::SaveState: return new SaveStateMessage(_messageBuffer, messageLength);
case MessageType::InputData: return new InputDataMessage(_messageBuffer, messageLength);
@ -77,7 +70,7 @@ NetMessage* GameConnection::ReadMessage()
return nullptr;
}
void GameConnection::SendNetMessage(NetMessage& message)
void GameConnection::SendNetMessage(NetMessage &message)
{
auto lock = _socketLock.AcquireSafe();
message.Send(*_socket.get());
@ -97,8 +90,7 @@ bool GameConnection::ConnectionError()
void GameConnection::ProcessMessages()
{
NetMessage* message;
while ((message = ReadMessage()) != nullptr)
{
while((message = ReadMessage()) != nullptr) {
//Loop until all messages have been processed
message->Initialize();
ProcessMessage(message);

View file

@ -30,7 +30,7 @@ private:
void ReadSocket();
bool ExtractMessage(void* buffer, uint32_t& messageLength);
bool ExtractMessage(void *buffer, uint32_t &messageLength);
NetMessage* ReadMessage();
virtual void ProcessMessage(NetMessage* message) = 0;
@ -44,5 +44,5 @@ public:
bool ConnectionError();
void ProcessMessages();
void SendNetMessage(NetMessage& message);
void SendNetMessage(NetMessage &message);
};

View file

@ -13,18 +13,15 @@ private:
bool _paused = false;
protected:
void Serialize(Serializer& s) override
void Serialize(Serializer &s) override
{
s.Stream(_romFilename, _sha1Hash, _controllerPort, _paused);
}
public:
GameInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length)
{
}
GameInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
GameInformationMessage(string filepath, string sha1Hash, uint8_t port, bool paused) : NetMessage(
MessageType::GameInformation)
GameInformationMessage(string filepath, string sha1Hash, uint8_t port, bool paused) : NetMessage(MessageType::GameInformation)
{
_romFilename = FolderUtilities::GetFilename(filepath, true);
_sha1Hash = sha1Hash;

View file

@ -34,8 +34,7 @@ GameServer::~GameServer()
Stop();
shared_ptr<ControlManager> controlManager = _console->GetControlManager();
if (controlManager)
{
if(controlManager) {
controlManager->UnregisterInputRecorder(this);
controlManager->UnregisterInputProvider(this);
}
@ -44,8 +43,7 @@ GameServer::~GameServer()
void GameServer::RegisterServerInput()
{
shared_ptr<ControlManager> controlManager = _console->GetControlManager();
if (controlManager)
{
if(controlManager) {
controlManager->RegisterInputRecorder(this);
controlManager->RegisterInputProvider(this);
}
@ -53,17 +51,13 @@ void GameServer::RegisterServerInput()
void GameServer::AcceptConnections()
{
while (true)
{
while(true) {
shared_ptr<Socket> socket = _listener->Accept();
if (!socket->ConnectionError())
{
if(!socket->ConnectionError()) {
auto connection = shared_ptr<GameServerConnection>(new GameServerConnection(_console, socket, _password));
_console->GetNotificationManager()->RegisterNotificationListener(connection);
_openConnections.push_back(connection);
}
else
{
} else {
break;
}
}
@ -73,63 +67,48 @@ void GameServer::AcceptConnections()
void GameServer::UpdateConnections()
{
vector<shared_ptr<GameServerConnection>> connectionsToRemove;
for (shared_ptr<GameServerConnection> connection : _openConnections)
{
if (connection->ConnectionError())
{
for(shared_ptr<GameServerConnection> connection : _openConnections) {
if(connection->ConnectionError()) {
connectionsToRemove.push_back(connection);
}
else
{
} else {
connection->ProcessMessages();
}
}
for (shared_ptr<GameServerConnection> gameConnection : connectionsToRemove)
{
for(shared_ptr<GameServerConnection> gameConnection : connectionsToRemove) {
_openConnections.remove(gameConnection);
}
}
list<shared_ptr<GameServerConnection>> GameServer::GetConnectionList()
{
if (GameServer::Started())
{
if(GameServer::Started()) {
return Instance->_openConnections;
}
else
{
} else {
return list<shared_ptr<GameServerConnection>>();
}
}
bool GameServer::SetInput(BaseControlDevice* device)
bool GameServer::SetInput(BaseControlDevice *device)
{
uint8_t port = device->GetPort();
if (device->GetControllerType() == ControllerType::Multitap)
{
if(device->GetControllerType() == ControllerType::Multitap) {
//Need special handling for the multitap, merge data from P3/4/5 with P1 (or P2, depending which port the multitap is plugged into)
GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(port);
if (connection)
{
if(connection) {
((Multitap*)device)->SetControllerState(0, connection->GetState());
}
for (int i = 2; i < 5; i++)
{
for(int i = 2; i < 5; i++) {
GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(i);
if (connection)
{
if(connection) {
((Multitap*)device)->SetControllerState(i - 1, connection->GetState());
}
}
}
else
{
} else {
GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(port);
if (connection)
{
if(connection) {
//Device is controlled by a client
device->SetRawState(connection->GetState());
return true;
@ -142,12 +121,9 @@ bool GameServer::SetInput(BaseControlDevice* device)
void GameServer::RecordInput(vector<shared_ptr<BaseControlDevice>> devices)
{
for (shared_ptr<BaseControlDevice>& device : devices)
{
for (shared_ptr<GameServerConnection> connection : _openConnections)
{
if (!connection->ConnectionError())
{
for(shared_ptr<BaseControlDevice> &device : devices) {
for(shared_ptr<GameServerConnection> connection : _openConnections) {
if(!connection->ConnectionError()) {
//Send movie stream
connection->SendMovieData(device->GetPort(), device->GetRawState());
}
@ -155,10 +131,9 @@ void GameServer::RecordInput(vector<shared_ptr<BaseControlDevice>> devices)
}
}
void GameServer::ProcessNotification(ConsoleNotificationType type, void* parameter)
void GameServer::ProcessNotification(ConsoleNotificationType type, void * parameter)
{
if (type == ConsoleNotificationType::GameLoaded)
{
if(type == ConsoleNotificationType::GameLoaded) {
//Register the server as an input provider/recorder
RegisterServerInput();
}
@ -171,10 +146,9 @@ void GameServer::Exec()
_listener->Listen(10);
_stop = false;
_initialized = true;
MessageManager::DisplayMessage("NetPlay", "ServerStarted", std::to_string(_port));
MessageManager::DisplayMessage("NetPlay" , "ServerStarted", std::to_string(_port));
while (!_stop)
{
while(!_stop) {
AcceptConnections();
UpdateConnections();
@ -198,28 +172,23 @@ void GameServer::StartServer(shared_ptr<Console> console, uint16_t port, string
void GameServer::StopServer()
{
if (Instance)
{
if(Instance) {
Instance.reset();
}
}
bool GameServer::Started()
{
if (Instance)
{
if(Instance) {
return Instance->_initialized;
}
else
{
} else {
return false;
}
}
string GameServer::GetHostPlayerName()
{
if (GameServer::Started())
{
if(GameServer::Started()) {
return Instance->_hostPlayerName;
}
return "";
@ -227,8 +196,7 @@ string GameServer::GetHostPlayerName()
uint8_t GameServer::GetHostControllerPort()
{
if (GameServer::Started())
{
if(GameServer::Started()) {
return Instance->_hostControllerPort;
}
return GameConnection::SpectatorPort;
@ -236,11 +204,9 @@ uint8_t GameServer::GetHostControllerPort()
void GameServer::SetHostControllerPort(uint8_t port)
{
if (GameServer::Started())
{
if(GameServer::Started()) {
Instance->_console->Lock();
if (port == GameConnection::SpectatorPort || GetAvailableControllers() & (1 << port))
{
if(port == GameConnection::SpectatorPort || GetAvailableControllers() & (1 << port)) {
//Port is available
Instance->_hostControllerPort = port;
SendPlayerList();
@ -252,10 +218,8 @@ void GameServer::SetHostControllerPort(uint8_t port)
uint8_t GameServer::GetAvailableControllers()
{
uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1;
for (PlayerInfo& playerInfo : GetPlayerList())
{
if (playerInfo.ControllerPort < BaseControlDevice::PortCount)
{
for(PlayerInfo &playerInfo : GetPlayerList()) {
if(playerInfo.ControllerPort < BaseControlDevice::PortCount) {
availablePorts &= ~(1 << playerInfo.ControllerPort);
}
}
@ -272,8 +236,7 @@ vector<PlayerInfo> GameServer::GetPlayerList()
playerInfo.IsHost = true;
playerList.push_back(playerInfo);
for (shared_ptr<GameServerConnection>& connection : GetConnectionList())
{
for(shared_ptr<GameServerConnection> &connection : GetConnectionList()) {
playerInfo.Name = connection->GetPlayerName();
playerInfo.ControllerPort = connection->GetControllerPort();
playerInfo.IsHost = false;
@ -287,8 +250,7 @@ void GameServer::SendPlayerList()
{
vector<PlayerInfo> playerList = GetPlayerList();
for (shared_ptr<GameServerConnection>& connection : GetConnectionList())
{
for(shared_ptr<GameServerConnection> &connection : GetConnectionList()) {
//Send player list update to all connections
PlayerListMessage message(playerList);
connection->SendNetMessage(message);

View file

@ -50,9 +50,9 @@ public:
static list<shared_ptr<GameServerConnection>> GetConnectionList();
bool SetInput(BaseControlDevice* device) override;
bool SetInput(BaseControlDevice *device) override;
void RecordInput(vector<shared_ptr<BaseControlDevice>> devices) override;
// Inherited via INotificationListener
virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) override;
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
};

View file

@ -19,10 +19,9 @@
#include "BaseControlDevice.h"
#include "ServerInformationMessage.h"
GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = {};
GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = { };
GameServerConnection::GameServerConnection(shared_ptr<Console> console, shared_ptr<Socket> socket,
string serverPassword) : GameConnection(console, socket)
GameServerConnection::GameServerConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, string serverPassword) : GameConnection(console, socket)
{
//Server-side connection
_serverPassword = serverPassword;
@ -32,10 +31,8 @@ GameServerConnection::GameServerConnection(shared_ptr<Console> console, shared_p
GameServerConnection::~GameServerConnection()
{
if (!_playerName.empty())
{
MessageManager::DisplayMessage(
"NetPlay", _playerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected.");
if(!_playerName.empty()) {
MessageManager::DisplayMessage("NetPlay", _playerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected.");
}
UnregisterNetPlayDevice(this);
@ -47,8 +44,7 @@ void GameServerConnection::SendServerInformation()
std::mt19937 engine(rd());
std::uniform_int_distribution<> dist((int)' ', (int)'~');
string hash(50, ' ');
for (int i = 0; i < 50; i++)
{
for(int i = 0; i < 50; i++) {
int random = dist(engine);
hash[i] = (char)random;
}
@ -63,8 +59,7 @@ void GameServerConnection::SendGameInformation()
{
_console->Lock();
RomInfo romInfo = _console->GetRomInfo();
GameInformationMessage gameInfo(romInfo.RomFile.GetFileName(), _console->GetCartridge()->GetSha1Hash(),
_controllerPort, _console->IsPaused());
GameInformationMessage gameInfo(romInfo.RomFile.GetFileName(), _console->GetCartridge()->GetSha1Hash(), _controllerPort, _console->IsPaused());
SendNetMessage(gameInfo);
SaveStateMessage saveState(_console);
SendNetMessage(saveState);
@ -73,8 +68,7 @@ void GameServerConnection::SendGameInformation()
void GameServerConnection::SendMovieData(uint8_t port, ControlDeviceState state)
{
if (_handshakeCompleted)
{
if(_handshakeCompleted) {
MovieDataMessage message(state, port);
SendNetMessage(message);
}
@ -89,8 +83,7 @@ void GameServerConnection::SendForceDisconnectMessage(string disconnectMessage)
void GameServerConnection::PushState(ControlDeviceState state)
{
if (_inputData.size() == 0 || state != _inputData.back())
{
if(_inputData.size() == 0 || state != _inputData.back()) {
_inputData.clear();
_inputData.push_back(state);
}
@ -100,11 +93,9 @@ ControlDeviceState GameServerConnection::GetState()
{
size_t inputBufferSize = _inputData.size();
ControlDeviceState stateData;
if (inputBufferSize > 0)
{
if(inputBufferSize > 0) {
stateData = _inputData.front();
if (inputBufferSize > 1)
{
if(inputBufferSize > 1) {
//Always keep the last one the client sent, it will be used until a new one is received
_inputData.pop_front();
}
@ -115,23 +106,18 @@ ControlDeviceState GameServerConnection::GetState()
void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message)
{
//Send the game's current state to the client and register the controller
if (message->IsValid(_console->GetSettings()->GetVersion()))
{
if (message->CheckPassword(_serverPassword, _connectionHash))
{
if(message->IsValid(_console->GetSettings()->GetVersion())) {
if(message->CheckPassword(_serverPassword, _connectionHash)) {
_console->Lock();
_controllerPort = message->IsSpectator() ? GameConnection::SpectatorPort : GetFirstFreeControllerPort();
_playerName = message->GetPlayerName();
string playerPortMessage = _controllerPort == GameConnection::SpectatorPort
? "Spectator"
: "Player " + std::to_string(_controllerPort + 1);
string playerPortMessage = _controllerPort == GameConnection::SpectatorPort ? "Spectator" : "Player " + std::to_string(_controllerPort + 1);
MessageManager::DisplayMessage("NetPlay", _playerName + " (" + playerPortMessage + ") connected.");
if (_console->GetCartridge())
{
if(_console->GetCartridge()) {
SendGameInformation();
}
@ -139,32 +125,24 @@ void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message)
RegisterNetPlayDevice(this, _controllerPort);
GameServer::SendPlayerList();
_console->Unlock();
}
else
{
} else {
SendForceDisconnectMessage("The password you provided did not match - you have been disconnected.");
}
}
else
{
SendForceDisconnectMessage(
"Server is using a different version of Mesen-S (" + _console->GetSettings()->GetVersionString() +
") - you have been disconnected.");
} else {
SendForceDisconnectMessage("Server is using a different version of Mesen-S (" + _console->GetSettings()->GetVersionString() + ") - you have been disconnected.");
MessageManager::DisplayMessage("NetPlay", + "NetplayVersionMismatch", message->GetPlayerName());
}
}
void GameServerConnection::ProcessMessage(NetMessage* message)
{
switch (message->GetType())
{
switch(message->GetType()) {
case MessageType::HandShake:
ProcessHandshakeResponse((HandShakeMessage*)message);
break;
case MessageType::InputData:
if (!_handshakeCompleted)
{
if(!_handshakeCompleted) {
SendForceDisconnectMessage("Handshake has not been completed - invalid packet");
return;
}
@ -172,8 +150,7 @@ void GameServerConnection::ProcessMessage(NetMessage* message)
break;
case MessageType::SelectController:
if (!_handshakeCompleted)
{
if(!_handshakeCompleted) {
SendForceDisconnectMessage("Handshake has not been completed - invalid packet");
return;
}
@ -188,28 +165,20 @@ void GameServerConnection::ProcessMessage(NetMessage* message)
void GameServerConnection::SelectControllerPort(uint8_t port)
{
_console->Lock();
if (port == GameConnection::SpectatorPort)
{
if(port == GameConnection::SpectatorPort) {
//Client wants to be a spectator, make sure we are not using any controller
UnregisterNetPlayDevice(this);
_controllerPort = port;
}
else
{
} else {
GameServerConnection* netPlayDevice = GetNetPlayDevice(port);
if (netPlayDevice == this)
{
if(netPlayDevice == this) {
//Nothing to do, we're already this player
}
else if (netPlayDevice == nullptr)
{
} else if(netPlayDevice == nullptr) {
//This port is free, we can switch
UnregisterNetPlayDevice(this);
RegisterNetPlayDevice(this, port);
_controllerPort = port;
}
else
{
} else {
//Another player is using this port, we can't use it
}
}
@ -220,8 +189,7 @@ void GameServerConnection::SelectControllerPort(uint8_t port)
void GameServerConnection::ProcessNotification(ConsoleNotificationType type, void* parameter)
{
switch (type)
{
switch(type) {
case ConsoleNotificationType::GamePaused:
case ConsoleNotificationType::GameLoaded:
case ConsoleNotificationType::GameResumed:
@ -232,8 +200,7 @@ void GameServerConnection::ProcessNotification(ConsoleNotificationType type, voi
SendGameInformation();
break;
case ConsoleNotificationType::BeforeEmulationStop:
{
case ConsoleNotificationType::BeforeEmulationStop: {
//Make clients unload the current game
GameInformationMessage gameInfo("", "0000000000000000000000000000000000000000", _controllerPort, true);
SendNetMessage(gameInfo);
@ -252,12 +219,9 @@ void GameServerConnection::RegisterNetPlayDevice(GameServerConnection* device, u
void GameServerConnection::UnregisterNetPlayDevice(GameServerConnection* device)
{
if (device != nullptr)
{
for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
if (GameServerConnection::_netPlayDevices[i] == device)
{
if(device != nullptr) {
for(int i = 0; i < BaseControlDevice::PortCount; i++) {
if(GameServerConnection::_netPlayDevices[i] == device) {
GameServerConnection::_netPlayDevices[i] = nullptr;
break;
}
@ -273,10 +237,8 @@ GameServerConnection* GameServerConnection::GetNetPlayDevice(uint8_t port)
uint8_t GameServerConnection::GetFirstFreeControllerPort()
{
uint8_t hostPost = GameServer::GetHostControllerPort();
for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
if (hostPost != i && GameServerConnection::_netPlayDevices[i] == nullptr)
{
for(int i = 0; i < BaseControlDevice::PortCount; i++) {
if(hostPost != i && GameServerConnection::_netPlayDevices[i] == nullptr) {
return i;
}
}

View file

@ -19,7 +19,7 @@
#include "../Utilities/VirtualFile.h"
#include "../Utilities/Serializer.h"
Gameboy* Gameboy::Create(Console* console, VirtualFile& romFile, bool sgbEnabled)
Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled)
{
vector<uint8_t> romData;
romFile.ReadFile(romData);
@ -31,30 +31,22 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile& romFile, bool sgbEnabled
MessageManager::Log("File: " + romFile.GetFileName());
MessageManager::Log("Game: " + header.GetCartName());
MessageManager::Log("Cart Type: " + std::to_string(header.CartType));
switch (header.CgbFlag & 0xC0)
{
case 0x00: MessageManager::Log("Supports: Game Boy");
break;
case 0x80: MessageManager::Log("Supports: Game Boy Color (compatible with GB)");
break;
case 0xC0: MessageManager::Log("Supports: Game Boy Color only");
break;
switch(header.CgbFlag & 0xC0) {
case 0x00: MessageManager::Log("Supports: Game Boy"); break;
case 0x80: MessageManager::Log("Supports: Game Boy Color (compatible with GB)"); break;
case 0xC0: MessageManager::Log("Supports: Game Boy Color only"); break;
}
MessageManager::Log("File size: " + std::to_string(romData.size() / 1024) + " KB");
if (header.GetCartRamSize() > 0)
{
string sizeString = header.GetCartRamSize() > 1024
? std::to_string(header.GetCartRamSize() / 1024) + " KB"
: std::to_string(header.GetCartRamSize()) + " bytes";
if(header.GetCartRamSize() > 0) {
string sizeString = header.GetCartRamSize() > 1024 ? std::to_string(header.GetCartRamSize() / 1024) + " KB" : std::to_string(header.GetCartRamSize()) + " bytes";
MessageManager::Log("Cart RAM size: " + sizeString + (header.HasBattery() ? " (with battery)" : ""));
}
MessageManager::Log("-----------------------------");
GbCart* cart = GbCartFactory::CreateCart(header.CartType);
if (cart)
{
if(cart) {
Gameboy* gb = new Gameboy();
gb->Init(console, cart, romData, header, sgbEnabled);
return gb;
@ -63,8 +55,7 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile& romFile, bool sgbEnabled
return nullptr;
}
void Gameboy::Init(Console* console, GbCart* cart, std::vector<uint8_t>& romData, GameboyHeader& header,
bool sgbEnabled)
void Gameboy::Init(Console* console, GbCart* cart, std::vector<uint8_t>& romData, GameboyHeader& header, bool sgbEnabled)
{
_console = console;
_cart.reset(cart);
@ -80,20 +71,15 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector<uint8_t>& romData
shared_ptr<EmuSettings> settings = console->GetSettings();
GameboyConfig cfg = settings->GetGameboyConfig();
GameboyModel model = cfg.Model;
if (model == GameboyModel::Auto)
{
if ((header.CgbFlag & 0x80) != 0)
{
if(model == GameboyModel::Auto) {
if((header.CgbFlag & 0x80) != 0) {
model = GameboyModel::GameboyColor;
}
else
{
} else {
model = GameboyModel::SuperGameboy;
}
}
if (!sgbEnabled && model == GameboyModel::SuperGameboy)
{
if(!sgbEnabled && model == GameboyModel::SuperGameboy) {
//SGB bios isn't available, use gameboy color mode instead
model = GameboyModel::GameboyColor;
}
@ -112,20 +98,15 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector<uint8_t>& romData
_bootRomSize = 0;
FirmwareType type = FirmwareType::Gameboy;
if (_model == GameboyModel::SuperGameboy)
{
if(_model == GameboyModel::SuperGameboy) {
type = cfg.UseSgb2 ? FirmwareType::Sgb2GameboyCpu : FirmwareType::Sgb1GameboyCpu;
}
else if (_model == GameboyModel::GameboyColor)
{
} else if(_model == GameboyModel::GameboyColor) {
type = FirmwareType::GameboyColor;
}
_bootRomSize = cgbMode ? 9 * 256 : 256;
if (!FirmwareHelper::LoadGbBootRom(console, &_bootRom, type))
{
switch (_model)
{
if(!FirmwareHelper::LoadGbBootRom(console, &_bootRom, type)) {
switch(_model) {
default:
case GameboyModel::Gameboy:
_bootRom = new uint8_t[_bootRomSize];
@ -139,12 +120,9 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector<uint8_t>& romData
case GameboyModel::SuperGameboy:
_bootRom = new uint8_t[_bootRomSize];
if (cfg.UseSgb2)
{
if(cfg.UseSgb2) {
memcpy(_bootRom, sgb2BootRom, _bootRomSize);
}
else
{
} else {
memcpy(_bootRom, sgbBootRom, _bootRomSize);
}
break;
@ -206,24 +184,21 @@ void Gameboy::Exec()
void Gameboy::Run(uint64_t runUntilClock)
{
while (_memoryManager->GetCycleCount() < runUntilClock)
{
while(_memoryManager->GetCycleCount() < runUntilClock) {
_cpu->Exec();
}
}
void Gameboy::LoadBattery()
{
if (_hasBattery)
{
if(_hasBattery) {
_console->GetBatteryManager()->LoadBattery(".srm", _cartRam, _cartRamSize);
}
}
void Gameboy::SaveBattery()
{
if (_hasBattery)
{
if(_hasBattery) {
_console->GetBatteryManager()->SaveBattery(".srm", _cartRam, _cartRamSize);
}
}
@ -244,8 +219,7 @@ GbState Gameboy::GetState()
uint32_t Gameboy::DebugGetMemorySize(SnesMemoryType type)
{
switch (type)
{
switch(type) {
case SnesMemoryType::GbPrgRom: return _prgRomSize;
case SnesMemoryType::GbWorkRam: return _workRamSize;
case SnesMemoryType::GbCartRam: return _cartRamSize;
@ -259,8 +233,7 @@ uint32_t Gameboy::DebugGetMemorySize(SnesMemoryType type)
uint8_t* Gameboy::DebugGetMemory(SnesMemoryType type)
{
switch (type)
{
switch(type) {
case SnesMemoryType::GbPrgRom: return _prgRom;
case SnesMemoryType::GbWorkRam: return _workRam;
case SnesMemoryType::GbCartRam: return _cartRam;
@ -287,17 +260,16 @@ GbCpu* Gameboy::GetCpu()
return _cpu.get();
}
void Gameboy::GetSoundSamples(int16_t* & samples, uint32_t& sampleCount)
void Gameboy::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount)
{
_apu->GetSoundSamples(samples, sampleCount);
}
AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr)
{
AddressInfo addrInfo = {-1, SnesMemoryType::Register};
AddressInfo addrInfo = { -1, SnesMemoryType::Register };
if (addr >= 0xFF80 && addr <= 0xFFFE)
{
if(addr >= 0xFF80 && addr <= 0xFFFE) {
addrInfo.Address = addr & 0x7F;
addrInfo.Type = SnesMemoryType::GbHighRam;
return addrInfo;
@ -305,30 +277,22 @@ AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr)
uint8_t* ptr = _memoryManager->GetMappedBlock(addr);
if (!ptr)
{
if(!ptr) {
return addrInfo;
}
ptr += (addr & 0xFF);
if (ptr >= _prgRom && ptr < _prgRom + _prgRomSize)
{
if(ptr >= _prgRom && ptr < _prgRom + _prgRomSize) {
addrInfo.Address = (int32_t)(ptr - _prgRom);
addrInfo.Type = SnesMemoryType::GbPrgRom;
}
else if (ptr >= _workRam && ptr < _workRam + _workRamSize)
{
} else if(ptr >= _workRam && ptr < _workRam + _workRamSize) {
addrInfo.Address = (int32_t)(ptr - _workRam);
addrInfo.Type = SnesMemoryType::GbWorkRam;
}
else if (ptr >= _cartRam && ptr < _cartRam + _cartRamSize)
{
} else if(ptr >= _cartRam && ptr < _cartRam + _cartRamSize) {
addrInfo.Address = (int32_t)(ptr - _cartRam);
addrInfo.Type = SnesMemoryType::GbCartRam;
}
else if (ptr >= _bootRom && ptr < _bootRom + _bootRomSize)
{
} else if(ptr >= _bootRom && ptr < _bootRom + _bootRomSize) {
addrInfo.Address = (int32_t)(ptr - _bootRom);
addrInfo.Type = SnesMemoryType::GbBootRom;
}
@ -337,16 +301,13 @@ AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr)
int32_t Gameboy::GetRelativeAddress(AddressInfo& absAddress)
{
if (absAddress.Type == SnesMemoryType::GbHighRam)
{
if(absAddress.Type == SnesMemoryType::GbHighRam) {
return 0xFF80 | (absAddress.Address & 0x7F);
}
for (int32_t i = 0; i < 0x10000; i += 0x100)
{
for(int32_t i = 0; i < 0x10000; i += 0x100) {
AddressInfo blockAddr = GetAbsoluteAddress(i);
if (blockAddr.Type == absAddress.Type && (blockAddr.Address & ~0xFF) == (absAddress.Address & ~0xFF))
{
if(blockAddr.Type == absAddress.Type && (blockAddr.Address & ~0xFF) == (absAddress.Address & ~0xFF)) {
return i | (absAddress.Address & 0xFF);
}
}

View file

@ -74,7 +74,7 @@ public:
GbPpu* GetPpu();
GbCpu* GetCpu();
void GetSoundSamples(int16_t* & samples, uint32_t& sampleCount);
void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount);
GbState GetState();
GameboyHeader GetHeader();

View file

@ -8,92 +8,60 @@
#include"../Utilities/HexUtilities.h"
constexpr const char* _opTemplate[256] = {
"NOP", "LD BC, e", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, d", "RLCA", "LD (a), SP", "ADD HL, BC",
"LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, d", "RRCA",
"STOP", "LD DE, e", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, d", "RLA", "JR r", "ADD HL, DE", "LD A, (DE)",
"DEC DE", "INC E", "DEC E", "LD E, d", "RRA",
"JR NZ, r", "LD HL, e", "LD (HL+), A", "INC HL", "INC H", "DEC H", "LD H, d", "DAA", "JR Z, r", "ADD HL, HL",
"LD A, (HL+)", "DEC HL", "INC L", "DEC L", "LD L, d", "CPL",
"JR NC, r", "LD SP, e", "LD (HL-), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), d", "SCF", "JR C, r",
"ADD HL, SP", "LD A, (HL-)", "DEC SP", "INC A", "DEC A", "LD A, d", "CCF",
"LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", "LD C, B", "LD C, C",
"LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A",
"LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", "LD E, B", "LD E, C",
"LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A",
"LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", "LD L, B", "LD L, C",
"LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A",
"LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E", "LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A", "LD A, B",
"LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A",
"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", "ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", "ADC A, B",
"ADC A, C", "ADC A, D", "ADC A, E", "ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A",
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", "SBC A, B", "SBC A, C", "SBC A, D",
"SBC A, E", "SBC A, H", "SBC A, L", "SBC A, (HL)", "SBC A, A",
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", "XOR B", "XOR C", "XOR D", "XOR E",
"XOR H", "XOR L", "XOR (HL)", "XOR A",
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", "CP B", "CP C", "CP D", "CP E", "CP H", "CP L",
"CP (HL)", "CP A",
"RET NZ", "POP BC", "JP NZ, a", "JP a", "CALL NZ, a", "PUSH BC", "ADD A, d", "RST 00H", "RET Z", "RET", "JP Z, a",
"PREFIX", "CALL Z, a", "CALL a", "ADC A, d", "RST 08H",
"RET NC", "POP DE", "JP NC, a", "ILL_D3", "CALL NC, a", "PUSH DE", "SUB d", "RST 10H", "RET C", "RETI", "JP C, a",
"ILL_DB", "CALL C, a", "ILL_DD", "SBC A, d", "RST 18H",
"LDH (c), A", "POP HL", "LD ($FF00+C), A", "ILL_E3", "ILL_E4", "PUSH HL", "AND d", "RST 20H", "ADD SP, d", "JP HL",
"LD (a), A", "ILL_EB", "ILL_EC", "ILL_ED", "XOR d", "RST 28H",
"LDH A, (c)", "POP AF", "LD A, ($FF00+C)", "DI", "ILL_F4", "PUSH AF", "OR d", "RST 30H", "LD HL, SP+d", "LD SP, HL",
"LD A, (a)", "EI", "ILL_FC", "ILL_FD", "CP d", "RST 38H"
"NOP", "LD BC, e", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, d", "RLCA", "LD (a), SP", "ADD HL, BC", "LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, d", "RRCA",
"STOP", "LD DE, e", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, d", "RLA", "JR r", "ADD HL, DE", "LD A, (DE)", "DEC DE", "INC E", "DEC E", "LD E, d", "RRA",
"JR NZ, r", "LD HL, e", "LD (HL+), A", "INC HL", "INC H", "DEC H", "LD H, d", "DAA", "JR Z, r", "ADD HL, HL", "LD A, (HL+)", "DEC HL", "INC L", "DEC L", "LD L, d", "CPL",
"JR NC, r", "LD SP, e", "LD (HL-), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), d", "SCF", "JR C, r", "ADD HL, SP", "LD A, (HL-)", "DEC SP", "INC A", "DEC A", "LD A, d", "CCF",
"LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", "LD C, B", "LD C, C", "LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A",
"LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", "LD E, B", "LD E, C", "LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A",
"LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", "LD L, B", "LD L, C", "LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A",
"LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E","LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A","LD A, B", "LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A",
"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", "ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", "ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", "ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A",
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", "SBC A, B", "SBC A, C", "SBC A, D", "SBC A, E", "SBC A, H", "SBC A, L", "SBC A, (HL)", "SBC A, A",
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A",
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A",
"RET NZ", "POP BC", "JP NZ, a", "JP a", "CALL NZ, a", "PUSH BC", "ADD A, d", "RST 00H", "RET Z", "RET", "JP Z, a", "PREFIX", "CALL Z, a","CALL a", "ADC A, d", "RST 08H",
"RET NC", "POP DE", "JP NC, a", "ILL_D3", "CALL NC, a", "PUSH DE", "SUB d", "RST 10H", "RET C", "RETI", "JP C, a", "ILL_DB", "CALL C, a","ILL_DD", "SBC A, d", "RST 18H",
"LDH (c), A", "POP HL", "LD ($FF00+C), A","ILL_E3","ILL_E4", "PUSH HL", "AND d", "RST 20H", "ADD SP, d", "JP HL", "LD (a), A", "ILL_EB", "ILL_EC", "ILL_ED", "XOR d", "RST 28H",
"LDH A, (c)", "POP AF", "LD A, ($FF00+C)","DI", "ILL_F4", "PUSH AF", "OR d", "RST 30H", "LD HL, SP+d", "LD SP, HL", "LD A, (a)", "EI", "ILL_FC", "ILL_FD", "CP d", "RST 38H"
};
constexpr const char* _cbTemplate[256] = {
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", "RRC B", "RRC C", "RRC D", "RRC E",
"RRC H", "RRC L", "RRC (HL)", "RRC A",
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", "RR B", "RR C", "RR D", "RR E", "RR H", "RR L",
"RR (HL)", "RR A",
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", "SRA B", "SRA C", "SRA D", "SRA E",
"SRA H", "SRA L", "SRA (HL)", "SRA A",
"SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", "SRL B", "SRL C", "SRL D",
"SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A",
"BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", "BIT 1, B",
"BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A",
"BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", "BIT 3, B",
"BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A",
"BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", "BIT 5, B",
"BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A",
"BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", "BIT 7, B",
"BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A",
"RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", "RES 1, B",
"RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A",
"RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", "RES 3, B",
"RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A",
"RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", "RES 5, B",
"RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A",
"RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", "RES 7, B",
"RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A",
"SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", "SET 1, B",
"SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A",
"SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", "SET 3, B",
"SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A",
"SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", "SET 5, B",
"SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A",
"SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", "SET 7, B",
"SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A",
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A",
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A",
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A",
"SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A",
"BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", "BIT 1, B", "BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A",
"BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", "BIT 3, B", "BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A",
"BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", "BIT 5, B", "BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A",
"BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", "BIT 7, B", "BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A",
"RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", "RES 1, B", "RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A",
"RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", "RES 3, B", "RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A",
"RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", "RES 5, B", "RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A",
"RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", "RES 7, B", "RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A",
"SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", "SET 1, B", "SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A",
"SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", "SET 3, B", "SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A",
"SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", "SET 5, B", "SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A",
"SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", "SET 7, B", "SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A",
};
constexpr const uint8_t _opSize[256] = {
1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1,
1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1,
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
1,3,1,1,1,1,2,1,3,1,1,1,1,1,2,1,
1,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1,
2,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1,
2,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,3,3,3,1,2,1,1,1,3,2,3,3,2,1,
1,1,3,1,3,1,2,1,1,1,3,1,3,1,2,1,
2,1,1,1,1,1,2,1,2,1,3,1,1,1,2,1,
2,1,1,1,1,1,2,1,2,1,3,1,1,1,2,1,
};
enum class AddrType : uint8_t
@ -107,106 +75,60 @@ enum class AddrType : uint8_t
};
static constexpr const AddrType _gbEffAddrType[256] = {
AddrType::None, AddrType::None, AddrType::BC, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::BC, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::DE, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::DE, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::HL, AddrType::HL, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::HL, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::Suff, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::C, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::C, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None,
AddrType::None, AddrType::None
AddrType::None,AddrType::None,AddrType::BC, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::BC, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::DE, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::DE, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::Suff,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::C,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,
AddrType::None,AddrType::None,AddrType::C,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None
};
void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr,
LabelManager* labelManager, EmuSettings* settings)
void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
{
FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly));
AddressInfo addrInfo{0, SnesMemoryType::GameboyMemory};
auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr)
{
AddressInfo addrInfo { 0, SnesMemoryType::GameboyMemory };
auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) {
addrInfo.Address = addr;
string label = labelManager ? labelManager->GetLabel(addrInfo) : "";
if (label.empty())
{
string label = labelManager ? labelManager->GetLabel(addrInfo) :"";
if(label.empty()) {
str.WriteAll('$', HexUtilities::ToHex(addr));
}
else
{
} else {
str.Write(label, true);
}
};
uint8_t* byteCode = info.GetByteCode();
const char* op = byteCode[0] == 0xCB ? _cbTemplate[byteCode[1]] : _opTemplate[byteCode[0]];
if (byteCode[0] == 0xCB)
{
if(byteCode[0] == 0xCB) {
byteCode++;
}
int i = 0;
while (op[i])
{
switch (op[i])
{
while(op[i]) {
switch(op[i]) {
//Relative jumps
case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0])));
break;
case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break;
//Jump addresses, memory addresses
case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8)));
break;
case 'c': getOperand((uint16_t)(0xFF00 | byteCode[1]));
break;
case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); break;
case 'c': getOperand((uint16_t)(0xFF00 | byteCode[1])); break;
//Immediate values
case 'd': str.WriteAll("$", HexUtilities::ToHex(byteCode[1]));
break;
case 'e': str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8))));
break;
case 'd': str.WriteAll("$", HexUtilities::ToHex(byteCode[1])); break;
case 'e': str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8)))); break;
default: str.Write(op[i]);
break;
default: str.Write(op[i]); break;
}
i++;
}
@ -216,8 +138,7 @@ void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_
int32_t GameboyDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, GbCpuState& state)
{
switch (_gbEffAddrType[info.GetOpCode()])
{
switch(_gbEffAddrType[info.GetOpCode()]) {
default:
case AddrType::None: return -1;
@ -226,8 +147,7 @@ int32_t GameboyDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* con
case AddrType::HL: return (state.H << 8) | state.L;
case AddrType::C: return 0xFF00 + state.C;
case AddrType::Suff:
if ((info.GetByteCode()[1] & 0x07) == 0x06)
{
if((info.GetByteCode()[1] & 0x07) == 0x06) {
return (state.H << 8) | state.L;
}
return -1;
@ -243,9 +163,8 @@ bool GameboyDisUtils::IsJumpToSub(uint8_t opCode)
{
return (
opCode == 0xC4 || opCode == 0xCC || opCode == 0xD4 || opCode == 0xDC || //CALL conditional
opCode == 0xCD || //Unconditional CALL
opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode
== 0xF7 || opCode == 0xFF //RST unconditional
opCode == 0xCD ||//Unconditional CALL
opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode == 0xF7 || opCode == 0xFF //RST unconditional
);
}

View file

@ -10,8 +10,7 @@ struct GbCpuState;
class GameboyDisUtils
{
public:
static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager,
EmuSettings* settings);
static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings);
static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, GbCpuState& state);
static uint8_t GetOpSize(uint8_t opCode);
static bool IsJumpToSub(uint8_t opCode);

View file

@ -20,8 +20,7 @@ struct GameboyHeader
uint32_t GetPrgRomSize()
{
if (PrgRomSize < 16)
{
if(PrgRomSize < 16) {
return 0x8000 << PrgRomSize;
}
return 0x8000;
@ -29,14 +28,12 @@ struct GameboyHeader
uint32_t GetCartRamSize()
{
if (CartType == 5 || CartType == 6)
{
if(CartType == 5 || CartType == 6) {
//MBC2 has 512x4bits of cart ram
return 0x200;
}
switch (CartRamSize)
{
switch(CartRamSize) {
case 0: return 0;
case 1: return 0x800;
case 2: return 0x2000;
@ -49,19 +46,10 @@ struct GameboyHeader
bool HasBattery()
{
switch (CartType)
{
case 0x03:
case 0x06:
case 0x09:
case 0x0D:
case 0x0F:
case 0x10:
case 0x13:
case 0x1B:
case 0x1E:
case 0x22:
case 0xFF:
switch(CartType) {
case 0x03: case 0x06: case 0x09: case 0x0D:
case 0x0F: case 0x10: case 0x13: case 0x1B:
case 0x1E: case 0x22: case 0xFF:
return true;
}
@ -71,10 +59,8 @@ struct GameboyHeader
string GetCartName()
{
int nameLength = 11;
for (int i = 0; i < 11; i++)
{
if (Title[i] == 0)
{
for(int i = 0; i < 11; i++) {
if(Title[i] == 0) {
nameLength = i;
break;
}
@ -82,12 +68,9 @@ struct GameboyHeader
string name = string(Title, nameLength);
size_t lastNonSpace = name.find_last_not_of(' ');
if (lastNonSpace != string::npos)
{
if(lastNonSpace != string::npos) {
return name.substr(0, lastNonSpace + 1);
}
else
{
} else {
return name;
}
}

View file

@ -37,13 +37,10 @@ void GbApu::Init(Console* console, Gameboy* gameboy)
blip_clear(_leftChannel);
blip_clear(_rightChannel);
if (_gameboy->IsSgb())
{
if(_gameboy->IsSgb()) {
blip_set_rates(_leftChannel, _gameboy->GetSgb()->GetClockRate(), GbApu::SampleRate);
blip_set_rates(_rightChannel, _gameboy->GetSgb()->GetClockRate(), GbApu::SampleRate);
}
else
{
} else {
blip_set_rates(_leftChannel, GbApu::ApuFrequency, GbApu::SampleRate);
blip_set_rates(_rightChannel, GbApu::ApuFrequency, GbApu::SampleRate);
}
@ -75,18 +72,11 @@ void GbApu::Run()
GameboyConfig cfg = _settings->GetGameboyConfig();
if (!_state.ApuEnabled)
{
if(!_state.ApuEnabled) {
_clockCounter += clocksToRun;
}
else
{
while (clocksToRun > 0)
{
uint32_t minTimer = std::min<uint32_t>({
clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer,
_noise->GetState().Timer
});
} else {
while(clocksToRun > 0) {
uint32_t minTimer = std::min<uint32_t>({ clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, _noise->GetState().Timer });
clocksToRun -= minTimer;
_square1->Exec(minTimer);
@ -101,8 +91,7 @@ void GbApu::Run()
(_noise->GetOutput() & _state.EnableLeftNoise) * cfg.NoiseVol / 100
) * (_state.LeftVolume + 1) * 40;
if (_prevLeftOutput != leftOutput)
{
if(_prevLeftOutput != leftOutput) {
blip_add_delta(_leftChannel, _clockCounter, leftOutput - _prevLeftOutput);
_prevLeftOutput = leftOutput;
}
@ -114,8 +103,7 @@ void GbApu::Run()
(_noise->GetOutput() & _state.EnableRightNoise) * cfg.NoiseVol / 100
) * (_state.RightVolume + 1) * 40;
if (_prevRightOutput != rightOutput)
{
if(_prevRightOutput != rightOutput) {
blip_add_delta(_rightChannel, _clockCounter, rightOutput - _prevRightOutput);
_prevRightOutput = rightOutput;
}
@ -124,8 +112,7 @@ void GbApu::Run()
}
}
if (!_gameboy->IsSgb() && _clockCounter >= 20000)
{
if(!_gameboy->IsSgb() && _clockCounter >= 20000) {
blip_end_frame(_leftChannel, _clockCounter);
blip_end_frame(_rightChannel, _clockCounter);
@ -136,7 +123,7 @@ void GbApu::Run()
}
}
void GbApu::GetSoundSamples(int16_t* & samples, uint32_t& sampleCount)
void GbApu::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount)
{
Run();
blip_end_frame(_leftChannel, _clockCounter);
@ -152,25 +139,20 @@ void GbApu::ClockFrameSequencer()
{
Run();
if (!_state.ApuEnabled)
{
if(!_state.ApuEnabled) {
return;
}
if ((_state.FrameSequenceStep & 0x01) == 0)
{
if((_state.FrameSequenceStep & 0x01) == 0) {
_square1->ClockLengthCounter();
_square2->ClockLengthCounter();
_wave->ClockLengthCounter();
_noise->ClockLengthCounter();
if ((_state.FrameSequenceStep & 0x03) == 2)
{
if((_state.FrameSequenceStep & 0x03) == 2) {
_square1->ClockSweepUnit();
}
}
else if (_state.FrameSequenceStep == 7)
{
} else if(_state.FrameSequenceStep == 7) {
_square1->ClockEnvelope();
_square2->ClockEnvelope();
_noise->ClockEnvelope();
@ -192,32 +174,17 @@ uint8_t GbApu::Read(uint16_t addr)
uint8_t GbApu::InternalRead(uint16_t addr)
{
switch (addr)
{
case 0xFF10:
case 0xFF11:
case 0xFF12:
case 0xFF13:
case 0xFF14:
switch(addr) {
case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14:
return _square1->Read(addr - 0xFF10);
case 0xFF16:
case 0xFF17:
case 0xFF18:
case 0xFF19:
case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19:
return _square2->Read(addr - 0xFF15);
case 0xFF1A:
case 0xFF1B:
case 0xFF1C:
case 0xFF1D:
case 0xFF1E:
case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E:
return _wave->Read(addr - 0xFF1A);
case 0xFF20:
case 0xFF21:
case 0xFF22:
case 0xFF23:
case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23:
return _noise->Read(addr - 0xFF1F);
case 0xFF24:
@ -250,22 +217,8 @@ uint8_t GbApu::InternalRead(uint16_t addr)
((_state.ApuEnabled && _square1->Enabled()) ? 0x01 : 0)
);
case 0xFF30:
case 0xFF31:
case 0xFF32:
case 0xFF33:
case 0xFF34:
case 0xFF35:
case 0xFF36:
case 0xFF37:
case 0xFF38:
case 0xFF39:
case 0xFF3A:
case 0xFF3B:
case 0xFF3C:
case 0xFF3D:
case 0xFF3E:
case 0xFF3F:
case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37:
case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F:
return _wave->ReadRam(addr);
}
@ -277,49 +230,30 @@ void GbApu::Write(uint16_t addr, uint8_t value)
{
Run();
if (!_state.ApuEnabled)
{
if (addr == 0xFF11 || addr == 0xFF16 || addr == 0xFF20)
{
if(!_state.ApuEnabled) {
if(addr == 0xFF11 || addr == 0xFF16 || addr == 0xFF20) {
//Allow writes to length counter, but not the upper 2 bits (square duty)
value &= 0x3F;
}
else if (addr < 0xFF26 && addr != 0xFF1B)
{
} else if(addr < 0xFF26 && addr != 0xFF1B) {
//Ignore all writes to these registers when APU is disabled
return;
}
}
switch (addr)
{
case 0xFF10:
case 0xFF11:
case 0xFF12:
case 0xFF13:
case 0xFF14:
switch(addr) {
case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14:
_square1->Write(addr - 0xFF10, value);
break;
case 0xFF16:
case 0xFF17:
case 0xFF18:
case 0xFF19:
case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19:
_square2->Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit
break;
case 0xFF1A:
case 0xFF1B:
case 0xFF1C:
case 0xFF1D:
case 0xFF1E:
case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E:
_wave->Write(addr - 0xFF1A, value);
break;
case 0xFF20:
case 0xFF21:
case 0xFF22:
case 0xFF23:
case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23:
_noise->Write(addr - 0xFF1F, value);
break;
@ -342,22 +276,17 @@ void GbApu::Write(uint16_t addr, uint8_t value)
_state.EnableRightSq1 = (value & 0x01) ? 0xFF : 0;
break;
case 0xFF26:
{
case 0xFF26: {
bool apuEnabled = (value & 0x80) != 0;
if (_state.ApuEnabled != apuEnabled)
{
if (!apuEnabled)
{
if(_state.ApuEnabled != apuEnabled) {
if(!apuEnabled) {
_square1->Disable();
_square2->Disable();
_wave->Disable();
_noise->Disable();
Write(0xFF24, 0);
Write(0xFF25, 0);
}
else
{
} else {
//When powered on, the frame sequencer is reset so that the next step will be 0,
//the square duty units are reset to the first step of the waveform, and the wave channel's sample buffer is reset to 0.
_state.FrameSequenceStep = 0;
@ -366,22 +295,8 @@ void GbApu::Write(uint16_t addr, uint8_t value)
}
break;
}
case 0xFF30:
case 0xFF31:
case 0xFF32:
case 0xFF33:
case 0xFF34:
case 0xFF35:
case 0xFF36:
case 0xFF37:
case 0xFF38:
case 0xFF39:
case 0xFF3A:
case 0xFF3B:
case 0xFF3C:
case 0xFF3D:
case 0xFF3E:
case 0xFF3F:
case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37:
case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F:
_wave->WriteRam(addr, value);
break;
}
@ -389,8 +304,7 @@ void GbApu::Write(uint16_t addr, uint8_t value)
uint8_t GbApu::ReadCgbRegister(uint16_t addr)
{
switch (addr)
{
switch(addr) {
case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4);
case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4);
}
@ -399,26 +313,20 @@ uint8_t GbApu::ReadCgbRegister(uint16_t addr)
return 0;
}
template <typename T>
void GbApu::ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled)
template<typename T>
void GbApu::ProcessLengthEnableFlag(uint8_t value, T &length, bool &lengthEnabled, bool &enabled)
{
bool newLengthEnabled = (value & 0x40) != 0;
if (newLengthEnabled && !lengthEnabled && (_state.FrameSequenceStep & 0x01) == 1)
{
if(newLengthEnabled && !lengthEnabled && (_state.FrameSequenceStep & 0x01) == 1) {
//"Extra length clocking occurs when writing to NRx4 when the frame sequencer's next step is one that doesn't clock
//the length counter. In this case, if the length counter was PREVIOUSLY disabled and now enabled and the length counter
//is not zero, it is decremented. If this decrement makes it zero and trigger is clear, the channel is disabled."
if (length > 0)
{
if(length > 0) {
length--;
if (length == 0)
{
if (value & 0x80)
{
if(length == 0) {
if(value & 0x80) {
length = sizeof(T) == 1 ? 0x3F : 0xFF;
}
else
{
} else {
enabled = false;
}
}
@ -443,7 +351,5 @@ void GbApu::Serialize(Serializer& s)
s.Stream(_noise.get());
}
template void GbApu::ProcessLengthEnableFlag<uint8_t>(uint8_t value, uint8_t& length, bool& lengthEnabled,
bool& enabled);
template void GbApu::ProcessLengthEnableFlag<uint16_t>(uint8_t value, uint16_t& length, bool& lengthEnabled,
bool& enabled);
template void GbApu::ProcessLengthEnableFlag<uint8_t>(uint8_t value, uint8_t& length, bool& lengthEnabled, bool& enabled);
template void GbApu::ProcessLengthEnableFlag<uint16_t>(uint8_t value, uint16_t& length, bool& lengthEnabled, bool& enabled);

Some files were not shown because too many files have changed in this diff Show more