diff --git a/Core/AluMulDiv.cpp b/Core/AluMulDiv.cpp index 9ad0d41..c9a9167 100644 --- a/Core/AluMulDiv.cpp +++ b/Core/AluMulDiv.cpp @@ -17,22 +17,28 @@ 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; } @@ -40,19 +46,21 @@ 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; } } } } - + _prevCpuCycle = cpuCycle; } @@ -60,12 +68,13 @@ uint8_t AluMulDiv::Read(uint16_t addr) { Run(true); - switch(addr) { - case 0x4214: return (uint8_t)_state.DivResult; - case 0x4215: return (uint8_t)(_state.DivResult >> 8); + switch (addr) + { + case 0x4214: return (uint8_t)_state.DivResult; + case 0x4215: return (uint8_t)(_state.DivResult >> 8); - case 0x4216: return (uint8_t)_state.MultOrRemainderResult; - case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8); + case 0x4216: return (uint8_t)_state.MultOrRemainderResult; + case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8); } throw std::runtime_error("ALU: invalid address"); @@ -75,33 +84,39 @@ void AluMulDiv::Write(uint16_t addr, uint8_t value) { Run(false); - switch(addr) { - case 0x4202: _state.MultOperand1 = value; break; - case 0x4203: - _state.MultOrRemainderResult = 0; - if(!_divCounter && !_multCounter) { - _multCounter = 8; + switch (addr) + { + case 0x4202: _state.MultOperand1 = value; + break; + case 0x4203: + _state.MultOrRemainderResult = 0; + if (!_divCounter && !_multCounter) + { + _multCounter = 8; - _state.MultOperand2 = value; - _state.DivResult = (value << 8) | _state.MultOperand1; - _shift = value; - } - break; + _state.MultOperand2 = value; + _state.DivResult = (value << 8) | _state.MultOperand1; + _shift = value; + } + 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; + case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value; + break; + case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8); + break; - if(!_divCounter && !_multCounter) { - _divCounter = 16; - _state.Divisor = value; - _shift = (value << 16); - } - break; + case 0x4206: + _state.MultOrRemainderResult = _state.Dividend; - default: throw std::runtime_error("ALU: invalid address"); + if (!_divCounter && !_multCounter) + { + _divCounter = 16; + _state.Divisor = value; + _shift = (value << 16); + } + break; + + default: throw std::runtime_error("ALU: invalid address"); } } @@ -110,10 +125,11 @@ 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 ); } diff --git a/Core/AluMulDiv.h b/Core/AluMulDiv.h index 82ad174..e219311 100644 --- a/Core/AluMulDiv.h +++ b/Core/AluMulDiv.h @@ -8,7 +8,7 @@ class Cpu; class AluMulDiv final : public ISerializable { private: - Cpu *_cpu; + Cpu* _cpu; uint64_t _prevCpuCycle = 0; @@ -17,10 +17,10 @@ private: uint32_t _shift = 0; uint8_t _multCounter = 0; uint8_t _divCounter = 0; - + public: void Initialize(Cpu* cpu); - + void Run(bool isRead); uint8_t Read(uint16_t addr); @@ -28,5 +28,5 @@ public: AluState GetState(); - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/Assembler.cpp b/Core/Assembler.cpp index 505243e..feec99d 100644 --- a/Core/Assembler.cpp +++ b/Core/Assembler.cpp @@ -9,60 +9,84 @@ #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& output, std::unordered_map& labels, bool firstPass, std::unordered_map& currentPassLabels) +void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector& output, + std::unordered_map& labels, bool firstPass, + std::unordered_map& 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 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& labels, bool firstPass) +AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData, + std::unordered_map& labels, bool firstPass) { bool isBinary = match.str(2).length() > 1 && match.str(2)[1] == '%'; //Immediate + binary: "#%" @@ -74,68 +98,93 @@ 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; } } @@ -143,175 +192,292 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineDa return GetAddrModeAndOperandSize(lineData, labels, firstPass); } -AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, bool firstPass) +AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData, + std::unordered_map& 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; } } @@ -331,41 +497,60 @@ 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& output, bool firstPass) +void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector& 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; @@ -375,22 +560,30 @@ 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); @@ -403,9 +596,12 @@ void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAdd } } - if(!foundMatch) { + if (!foundMatch) + { output.push_back(AssemblerSpecialCodes::InvalidInstruction); - } else { + } + else + { output.push_back(AssemblerSpecialCodes::EndOfLine); } } @@ -421,8 +617,10 @@ 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(); } _availableModesByOpName[CpuDisUtils::OpName[i]].emplace((int)CpuDisUtils::OpMode[i]); @@ -439,13 +637,17 @@ uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* as vector 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(); } @@ -454,15 +656,18 @@ 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); } } diff --git a/Core/Assembler.h b/Core/Assembler.h index e73995d..e344852 100644 --- a/Core/Assembler.h +++ b/Core/Assembler.h @@ -28,9 +28,13 @@ private: bool _needSecondPass; shared_ptr _labelManager; - void ProcessLine(string code, uint32_t& instructionAddress, vector& output, std::unordered_map& labels, bool firstPass, std::unordered_map& currentPassLabels); - AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, std::unordered_map& labels, bool firstPass); - AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, bool firstPass); + void ProcessLine(string code, uint32_t& instructionAddress, vector& output, + std::unordered_map& labels, bool firstPass, + std::unordered_map& currentPassLabels); + AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, + std::unordered_map& labels, bool firstPass); + AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, + bool firstPass); void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector& output, bool firstPass); bool IsOpModeAvailable(string& opCode, AddrMode mode); @@ -40,4 +44,4 @@ public: virtual ~Assembler(); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); -}; \ No newline at end of file +}; diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index 0e10dcf..c06327d 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -38,13 +38,16 @@ BaseCartridge::~BaseCartridge() delete[] _saveRam; } -shared_ptr BaseCartridge::CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile) +shared_ptr BaseCartridge::CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile) { - if(romFile.IsValid()) { + if (romFile.IsValid()) + { shared_ptr 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()); } } @@ -52,7 +55,8 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu vector romData; romFile.ReadFile(romData); - if(romData.size() < 0x4000) { + if (romData.size() < 0x4000) + { return nullptr; } @@ -60,24 +64,35 @@ shared_ptr 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; } @@ -86,19 +101,27 @@ shared_ptr 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; } } @@ -106,51 +129,65 @@ shared_ptr 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; } SnesCartInformation cartInfo; memcpy(&cartInfo, _prgRom + addr + 0x7FB0, sizeof(SnesCartInformation)); - + 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; } @@ -161,14 +198,16 @@ int32_t BaseCartridge::GetHeaderScore(uint32_t addr) void BaseCartridge::LoadRom() { //Find the best potential header among lorom/hirom + headerless/headered combinations - vector baseAddresses = { 0, 0x200, 0x8000, 0x8200, 0x408000, 0x408200 }; + vector 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; @@ -180,44 +219,57 @@ 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; } @@ -236,42 +288,48 @@ void BaseCartridge::LoadRom() CoprocessorType BaseCartridge::GetCoprocessorType() { - if((_cartInfo.RomType & 0x0F) >= 0x03) { - switch((_cartInfo.RomType & 0xF0) >> 4) { - case 0x00: return GetDspVersion(); - case 0x01: return CoprocessorType::GSU; - case 0x02: return CoprocessorType::OBC1; - case 0x03: return CoprocessorType::SA1; - case 0x04: return CoprocessorType::SDD1; - case 0x05: return CoprocessorType::RTC; - case 0x0E: - switch(_cartInfo.RomType) { - case 0xE3: return CoprocessorType::SGB; - case 0xE5: return CoprocessorType::Satellaview; - default: return CoprocessorType::None; - } - break; + if ((_cartInfo.RomType & 0x0F) >= 0x03) + { + switch ((_cartInfo.RomType & 0xF0) >> 4) + { + case 0x00: return GetDspVersion(); + case 0x01: return CoprocessorType::GSU; + case 0x02: return CoprocessorType::OBC1; + case 0x03: return CoprocessorType::SA1; + case 0x04: return CoprocessorType::SDD1; + case 0x05: return CoprocessorType::RTC; + case 0x0E: + switch (_cartInfo.RomType) + { + case 0xE3: return CoprocessorType::SGB; + case 0xE5: return CoprocessorType::Satellaview; + default: return CoprocessorType::None; + } + break; - case 0x0F: - switch(_cartInfo.CartridgeType) { - case 0x00: - _hasBattery = true; - _hasRtc = (_cartInfo.RomType & 0x0F) == 0x09; - return CoprocessorType::SPC7110; + case 0x0F: + switch (_cartInfo.CartridgeType) + { + case 0x00: + _hasBattery = true; + _hasRtc = (_cartInfo.RomType & 0x0F) == 0x09; + return CoprocessorType::SPC7110; - case 0x01: - _hasBattery = true; - return GetSt01xVersion(); + case 0x01: + _hasBattery = true; + return GetSt01xVersion(); - case 0x02: - _hasBattery = true; - return CoprocessorType::ST018; + case 0x02: + _hasBattery = true; + return CoprocessorType::ST018; - case 0x10: return CoprocessorType::CX4; - } - break; + case 0x10: return CoprocessorType::CX4; + } + break; } - } else if(GetGameCode() == "042J") { + } + else if (GetGameCode() == "042J") + { return CoprocessorType::SGB; } @@ -281,7 +339,8 @@ CoprocessorType BaseCartridge::GetCoprocessorType() CoprocessorType BaseCartridge::GetSt01xVersion() { string cartName = GetCartName(); - if(cartName == "2DAN MORITA SHOUGI") { + if (cartName == "2DAN MORITA SHOUGI") + { return CoprocessorType::ST011; } @@ -291,27 +350,36 @@ 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; } - + //Default to DSP1B return CoprocessorType::DSP1B; } void BaseCartridge::Reset() { - if(_coprocessor) { + if (_coprocessor) + { _coprocessor->Reset(); } - if(_bsxMemPack) { + if (_bsxMemPack) + { _bsxMemPack->Reset(); } } @@ -330,30 +398,43 @@ RomInfo BaseCartridge::GetRomInfo() vector BaseCartridge::GetOriginalPrgRom() { RomInfo romInfo = GetRomInfo(); - shared_ptr originalCart = BaseCartridge::CreateCartridge(_console, romInfo.RomFile, romInfo.PatchFile); - if(originalCart->_gameboy) { + shared_ptr 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(orgPrgRom, orgPrgRom + orgRomSize); - } else { - return vector(originalCart->DebugGetPrgRom(), originalCart->DebugGetPrgRom() + originalCart->DebugGetPrgRomSize()); + } + else + { + return vector(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); } } @@ -365,97 +446,122 @@ 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(new RomHandler(_prgRom, i, _prgRomSize, SnesMemoryType::PrgRom))); + for (uint32_t i = 0; i < _prgRomSize; i += 0x1000) + { + _prgRomHandlers. + push_back(unique_ptr(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((_prgRomSize - halfSize) / 0x1000, 1); - while(_prgRomHandlers.size() < fullSize / 0x1000) { - for(uint32_t i = 0; i < extraHandlers; i += 0x1000) { - _prgRomHandlers.push_back(unique_ptr(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(new RomHandler(_prgRom, halfSize + i, _prgRomSize, SnesMemoryType::PrgRom))); } } } - for(uint32_t i = 0; i < _saveRamSize; i += 0x1000) { - _saveRamHandlers.push_back(unique_ptr(new RamHandler(_saveRam, i, _saveRamSize, SnesMemoryType::SaveRam))); + for (uint32_t i = 0; i < _saveRamSize; i += 0x1000) + { + _saveRamHandlers.push_back( + unique_ptr(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); @@ -463,7 +569,9 @@ 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 @@ -484,11 +592,16 @@ 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; } @@ -503,23 +616,33 @@ void BaseCartridge::InitCoprocessor() _coprocessor.reset(NecDsp::InitCoprocessor(_coprocessorType, _console, _embeddedFirmware)); _necDsp = dynamic_cast(_coprocessor.get()); - if(_coprocessorType == CoprocessorType::SA1) { + if (_coprocessorType == CoprocessorType::SA1) + { _coprocessor.reset(new Sa1(_console)); _sa1 = dynamic_cast(_coprocessor.get()); _needCoprocSync = true; - } else if(_coprocessorType == CoprocessorType::GSU) { + } + else if (_coprocessorType == CoprocessorType::GSU) + { _coprocessor.reset(new Gsu(_console, _coprocessorRamSize)); _gsu = dynamic_cast(_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 emptyMemPack; _bsxMemPack.reset(new BsxMemoryPack(_console, emptyMemPack, false)); @@ -527,24 +650,31 @@ void BaseCartridge::InitCoprocessor() _coprocessor.reset(new BsxCart(_console, _bsxMemPack.get())); _bsx = dynamic_cast(_coprocessor.get()); - } else if(_coprocessorType == CoprocessorType::CX4) { + } + else if (_coprocessorType == CoprocessorType::CX4) + { _coprocessor.reset(new Cx4(_console)); _cx4 = dynamic_cast(_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(_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); @@ -557,13 +687,16 @@ 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); } @@ -575,19 +708,24 @@ 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 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); @@ -601,12 +739,15 @@ 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; @@ -620,29 +761,37 @@ 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(); } @@ -670,16 +819,19 @@ 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()); } } @@ -687,16 +839,20 @@ 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; @@ -705,8 +861,10 @@ 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; } @@ -714,9 +872,12 @@ 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; } } @@ -724,7 +885,8 @@ 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; @@ -736,50 +898,81 @@ 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 += ""; 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 += ""; + 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."); } @@ -788,13 +981,17 @@ 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("-----------------------------"); @@ -843,7 +1040,8 @@ 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(); } } @@ -866,4 +1064,4 @@ vector>& BaseCartridge::GetSaveRamHandlers() SpcFileData* BaseCartridge::GetSpcData() { return _spcData.get(); -} \ No newline at end of file +} diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index e54590b..a6705b4 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -23,7 +23,7 @@ enum class ConsoleRegion; class BaseCartridge : public ISerializable { private: - Console *_console; + Console* _console; vector> _prgRomHandlers; vector> _saveRamHandlers; @@ -32,12 +32,12 @@ private: bool _needCoprocSync = false; unique_ptr _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 _bsxMemPack; unique_ptr _gameboy; @@ -51,11 +51,11 @@ private: uint8_t* _prgRom = nullptr; uint8_t* _saveRam = nullptr; - + uint32_t _prgRomSize = 0; uint32_t _saveRamSize = 0; uint32_t _coprocessorRamSize = 0; - + shared_ptr _spcData; vector _embeddedFirmware; @@ -71,7 +71,7 @@ private: bool MapSpecificCarts(MemoryMappings& mm); void MapBsxMemoryPack(MemoryMappings& mm); void ApplyConfigOverrides(); - + void LoadRom(); void LoadSpc(); bool LoadGameboy(VirtualFile& romFile, bool sgbEnabled); @@ -85,13 +85,13 @@ private: public: virtual ~BaseCartridge(); - static shared_ptr CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile); + static shared_ptr CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile); void Reset(); void SaveBattery(); - void Init(MemoryMappings &mm); + void Init(MemoryMappings& mm); RomInfo GetRomInfo(); vector 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; } @@ -117,10 +117,11 @@ public: Gameboy* GetGameboy(); void RunCoprocessors(); - + __forceinline void SyncCoprocessors() { - if(_needCoprocSync) { + if (_needCoprocSync) + { _coprocessor->Run(); } } @@ -132,5 +133,5 @@ public: SpcFileData* GetSpcData(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/BaseControlDevice.cpp b/Core/BaseControlDevice.cpp index a500918..124f7d7 100644 --- a/Core/BaseControlDevice.cpp +++ b/Core/BaseControlDevice.cpp @@ -44,7 +44,8 @@ bool BaseControlDevice::IsExpansionDevice() void BaseControlDevice::StrobeProcessRead() { - if(_strobe) { + if (_strobe) + { RefreshStateBuffer(); } } @@ -54,7 +55,8 @@ void BaseControlDevice::StrobeProcessWrite(uint8_t value) bool prevStrobe = _strobe; _strobe = (value & 0x01) == 0x01; - if(prevStrobe && !_strobe) { + if (prevStrobe && !_strobe) + { RefreshStateBuffer(); } } @@ -82,17 +84,25 @@ 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 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; } @@ -102,10 +112,13 @@ 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++; @@ -117,24 +130,32 @@ 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 += ':'; } } @@ -149,7 +170,8 @@ 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); } } @@ -179,9 +201,12 @@ bool BaseControlDevice::IsPressed(uint8_t bit) void BaseControlDevice::SetBitValue(uint8_t bit, bool set) { - if(set) { + if (set) + { SetBit(bit); - } else { + } + else + { ClearBit(bit); } } @@ -204,23 +229,28 @@ 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); } } @@ -252,17 +282,18 @@ 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 state1, uint8_t button1, shared_ptr state2, uint8_t button2) +void BaseControlDevice::SwapButtons(shared_ptr state1, uint8_t button1, + shared_ptr state2, uint8_t button2) { bool pressed1 = state1->IsPressed(button1); bool pressed2 = state2->IsPressed(button2); @@ -270,15 +301,17 @@ void BaseControlDevice::SwapButtons(shared_ptr 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); diff --git a/Core/BaseControlDevice.h b/Core/BaseControlDevice.h index f73218f..920d464 100644 --- a/Core/BaseControlDevice.h +++ b/Core/BaseControlDevice.h @@ -20,8 +20,10 @@ protected: uint8_t _port; SimpleLock _stateLock; - virtual void RefreshStateBuffer() { } - + virtual void RefreshStateBuffer() + { + } + void EnsureCapacity(int32_t minBitCount); uint32_t GetByteIndex(uint8_t bit); virtual bool HasCoordinates(); @@ -41,9 +43,9 @@ protected: void SetMovement(MouseMovement mov); MouseMovement GetMovement(); - + virtual void InternalSetStateFromInput(); - + public: static constexpr uint8_t ExpDevicePort = 4; static constexpr uint8_t ConsoleInputPort = 5; @@ -58,27 +60,31 @@ public: bool IsPressed(uint8_t bit); MousePosition GetCoordinates(); - + void ClearState(); void SetBit(uint8_t bit); void ClearBit(uint8_t bit); void InvertBit(uint8_t bit); void SetBitValue(uint8_t bit, bool set); - + void SetTextState(string state); string GetTextState(); void SetStateFromInput(); - virtual void OnAfterSetState() { } - + + virtual void OnAfterSetState() + { + } + void SetRawState(ControlDeviceState state); ControlDeviceState GetRawState(); virtual ControllerType GetControllerType() = 0; virtual uint8_t ReadRam(uint16_t addr) = 0; virtual void WriteRam(uint16_t addr, uint8_t value) = 0; - - void static SwapButtons(shared_ptr state1, uint8_t button1, shared_ptr state2, uint8_t button2); - void Serialize(Serializer &s) override; + void static SwapButtons(shared_ptr state1, uint8_t button1, shared_ptr state2, + uint8_t button2); + + void Serialize(Serializer& s) override; }; diff --git a/Core/BaseCoprocessor.h b/Core/BaseCoprocessor.h index dbbd9bb..cb87901 100644 --- a/Core/BaseCoprocessor.h +++ b/Core/BaseCoprocessor.h @@ -10,8 +10,19 @@ public: virtual void Reset() = 0; - virtual void Run() { } - virtual void ProcessEndOfFrame() { } - virtual void LoadBattery() { } - virtual void SaveBattery() { } -}; \ No newline at end of file + virtual void Run() + { + } + + virtual void ProcessEndOfFrame() + { + } + + virtual void LoadBattery() + { + } + + virtual void SaveBattery() + { + } +}; diff --git a/Core/BaseRenderer.cpp b/Core/BaseRenderer.cpp index ceae15b..2c84932 100644 --- a/Core/BaseRenderer.cpp +++ b/Core/BaseRenderer.cpp @@ -9,7 +9,8 @@ BaseRenderer::BaseRenderer(shared_ptr console, bool registerAsMessageMa { _console = console; - if(registerAsMessageManager) { + if (registerAsMessageManager) + { //Only display messages on the master CPU's screen MessageManager::RegisterMessageManager(this); } @@ -37,34 +38,44 @@ void BaseRenderer::DrawToasts() int counter = 0; int lastHeight = 5; - for(shared_ptr toast : _toasts) { - if(counter < 6) { + for (shared_ptr 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 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); } @@ -72,19 +83,25 @@ 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++; @@ -94,10 +111,10 @@ std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_ return wrappedText; } -void BaseRenderer::DrawToast(shared_ptr toast, int &lastHeight) +void BaseRenderer::DrawToast(shared_ptr 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; @@ -117,24 +134,31 @@ 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; } @@ -171,13 +195,16 @@ 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++); } } @@ -185,4 +212,4 @@ void BaseRenderer::DrawCounters() bool BaseRenderer::IsMessageShown() { return !_toasts.empty(); -} +} diff --git a/Core/BaseRenderer.h b/Core/BaseRenderer.h index 7ccc297..dbe97e7 100644 --- a/Core/BaseRenderer.h +++ b/Core/BaseRenderer.h @@ -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; @@ -26,19 +26,20 @@ protected: uint32_t _screenWidth = 0; uint32_t _screenHeight = 0; - uint32_t _renderedFrameCount = 0; + uint32_t _renderedFrameCount = 0; BaseRenderer(shared_ptr console, bool registerAsMessageManager); virtual ~BaseRenderer(); - bool IsMessageShown(); + bool IsMessageShown(); void DisplayMessage(string title, string message); void DrawToasts(); - - void DrawToast(shared_ptr 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; + + void DrawToast(shared_ptr 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; void ShowFpsCounter(int lineNumber); void ShowLagCounter(int lineNumber); diff --git a/Core/BaseSoundManager.cpp b/Core/BaseSoundManager.cpp index dc95920..18ca558 100644 --- a/Core/BaseSoundManager.cpp +++ b/Core/BaseSoundManager.cpp @@ -5,25 +5,31 @@ 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; diff --git a/Core/BaseVideoFilter.cpp b/Core/BaseVideoFilter.cpp index 9318ced..c6a3916 100644 --- a/Core/BaseVideoFilter.cpp +++ b/Core/BaseVideoFilter.cpp @@ -36,8 +36,9 @@ 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; @@ -65,7 +66,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(); @@ -91,14 +92,15 @@ 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; } @@ -110,14 +112,19 @@ void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename pngBuffer = frameBuffer; shared_ptr 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); } @@ -131,16 +138,21 @@ 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++; @@ -150,4 +162,3 @@ void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType) MessageManager::DisplayMessage("ScreenshotSaved", FolderUtilities::GetFilename(ssFilename, true)); } - diff --git a/Core/BaseVideoFilter.h b/Core/BaseVideoFilter.h index ccfdde3..c557bac 100644 --- a/Core/BaseVideoFilter.h +++ b/Core/BaseVideoFilter.h @@ -20,7 +20,7 @@ protected: shared_ptr _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,12 +31,12 @@ 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(); - + void SetBaseFrameInfo(FrameInfo frameInfo); virtual FrameInfo GetFrameInfo(); -}; \ No newline at end of file +}; diff --git a/Core/BatteryManager.cpp b/Core/BatteryManager.cpp index 2d5926f..a969164 100644 --- a/Core/BatteryManager.cpp +++ b/Core/BatteryManager.cpp @@ -31,7 +31,8 @@ void BatteryManager::SetBatteryRecorder(shared_ptr 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 @@ -40,7 +41,8 @@ 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); } } @@ -49,21 +51,27 @@ void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t lengt vector BatteryManager::LoadBattery(string extension) { shared_ptr provider = _provider.lock(); - + vector 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 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); } @@ -76,4 +84,4 @@ void BatteryManager::LoadBattery(string extension, uint8_t* data, uint32_t lengt { vector batteryData = LoadBattery(extension); memcpy(data, batteryData.data(), std::min((uint32_t)batteryData.size(), length)); -} \ No newline at end of file +} diff --git a/Core/BatteryManager.h b/Core/BatteryManager.h index 5dc8e2a..a2e3b1c 100644 --- a/Core/BatteryManager.h +++ b/Core/BatteryManager.h @@ -30,9 +30,9 @@ public: void SetBatteryProvider(shared_ptr provider); void SetBatteryRecorder(shared_ptr recorder); - + void SaveBattery(string extension, uint8_t* data, uint32_t length); - + vector LoadBattery(string extension); void LoadBattery(string extension, uint8_t* data, uint32_t length); -}; \ No newline at end of file +}; diff --git a/Core/Breakpoint.cpp b/Core/Breakpoint.cpp index c2ffedf..c4637ce 100644 --- a/Core/Breakpoint.cpp +++ b/Core/Breakpoint.cpp @@ -3,22 +3,35 @@ #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; } } @@ -28,11 +41,12 @@ bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info) bool Breakpoint::HasBreakpointType(BreakpointType 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; - case BreakpointType::Write: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Write) != 0; + 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; + case BreakpointType::Write: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Write) != 0; } } diff --git a/Core/Breakpoint.h b/Core/Breakpoint.h index dc34199..ba8fe30 100644 --- a/Core/Breakpoint.h +++ b/Core/Breakpoint.h @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -enum class CpuType : uint8_t; +enum class CpuType : uint8_t; enum class SnesMemoryType; struct AddressInfo; enum class BreakpointType; @@ -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(); @@ -28,4 +28,4 @@ public: bool enabled; bool markEvent; char condition[1000]; -}; \ No newline at end of file +}; diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index 53f0c27..b507d59 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -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,7 +18,8 @@ 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; @@ -26,27 +27,34 @@ 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())); } - + _hasBreakpoint = true; _hasBreakpointType[i] = true; } @@ -60,61 +68,76 @@ void BreakpointManager::GetBreakpoints(Breakpoint* breakpoints, int& execs, int& reads = _breakpoints[static_cast(BreakpointType::Read)].size(); writes = _breakpoints[static_cast(BreakpointType::Write)].size(); - if (breakpoints == NULL) { + if (breakpoints == NULL) + { return; } int offset = 0; - for (auto it = _breakpoints[static_cast(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Execute)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Execute)].cend(); it++) + { breakpoints[offset++] = it->second; } - for (auto it = _breakpoints[static_cast(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Read)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Read)].cend(); it++) + { breakpoints[offset++] = it->second; } - for (auto it = _breakpoints[static_cast(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Write)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Write)].cend(); it++) + { breakpoints[offset++] = it->second; } } BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type) { - switch(type) { - default: - case MemoryOperationType::ExecOperand: - case MemoryOperationType::ExecOpCode: - return BreakpointType::Execute; + switch (type) + { + default: + case MemoryOperationType::ExecOperand: + case MemoryOperationType::ExecOpCode: + return BreakpointType::Execute; - case MemoryOperationType::DmaRead: - case MemoryOperationType::Read: - return BreakpointType::Read; + case MemoryOperationType::DmaRead: + case MemoryOperationType::Read: + return BreakpointType::Read; - case MemoryOperationType::DmaWrite: - case MemoryOperationType::Write: - return BreakpointType::Write; + case MemoryOperationType::DmaWrite: + case MemoryOperationType::Write: + return BreakpointType::Write; } } -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 &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& 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; } } diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h index f4a5ed8..1fb34c5 100644 --- a/Core/BreakpointManager.h +++ b/Core/BreakpointManager.h @@ -15,10 +15,10 @@ class BreakpointManager private: static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec - Debugger *_debugger; + Debugger* _debugger; CpuType _cpuType; - IEventManager *_eventManager; - + IEventManager* _eventManager; + unordered_map _breakpoints[BreakpointTypeCount]; unordered_map _rpnList[BreakpointTypeCount]; bool _hasBreakpoint; @@ -27,20 +27,21 @@ private: unique_ptr _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); -} \ No newline at end of file +} diff --git a/Core/BsxCart.cpp b/Core/BsxCart.cpp index 18d736c..a5ed890 100644 --- a/Core/BsxCart.cpp +++ b/Core/BsxCart.cpp @@ -28,13 +28,15 @@ 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(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam))); + for (uint32_t i = 0; i < _psRamSize / 0x1000; i++) + { + _psRamHandlers.push_back( + unique_ptr(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam))); } Reset(); } - + BsxCart::~BsxCart() { delete[] _psRam; @@ -43,14 +45,20 @@ 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; } @@ -59,20 +67,26 @@ 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; } @@ -88,7 +102,8 @@ 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 @@ -99,28 +114,34 @@ 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 mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, memPackHandlers, 8); mm->RegisterHandler(0x40, 0x7D, 0x0000, 0xFFFF, memPackHandlers, 0); @@ -128,25 +149,29 @@ 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); @@ -155,17 +180,20 @@ 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; } @@ -184,13 +212,14 @@ void BsxCart::Reset() void BsxCart::Serialize(Serializer& s) { - ArrayInfo psRam = { _psRam, _psRamSize }; - ArrayInfo regs = { _regs, 0x10 }; - ArrayInfo dirtyRegs = { _dirtyRegs, 0x10 }; + ArrayInfo psRam = {_psRam, _psRamSize}; + ArrayInfo regs = {_regs, 0x10}; + ArrayInfo dirtyRegs = {_dirtyRegs, 0x10}; s.Stream(psRam, regs, dirtyRegs, _dirty); s.Stream(_satellaview.get()); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { UpdateMemoryMappings(); } } @@ -207,7 +236,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() diff --git a/Core/BsxCart.h b/Core/BsxCart.h index c724073..63532f8 100644 --- a/Core/BsxCart.h +++ b/Core/BsxCart.h @@ -22,7 +22,7 @@ private: uint8_t _regs[0x10] = {}; uint8_t _dirtyRegs[0x10] = {}; bool _dirty = false; - + void UpdateMemoryMappings(); public: @@ -41,4 +41,4 @@ public: uint8_t* DebugGetPsRam(); uint32_t DebugGetPsRamSize(); -}; \ No newline at end of file +}; diff --git a/Core/BsxMemoryPack.cpp b/Core/BsxMemoryPack.cpp index 30e219f..861a35f 100644 --- a/Core/BsxMemoryPack.cpp +++ b/Core/BsxMemoryPack.cpp @@ -15,7 +15,8 @@ BsxMemoryPack::BsxMemoryPack(Console* console, vector& data, bool persi _calculatedSize = std::min(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(new BsxMemoryPackHandler(this, i * 0x1000))); } } @@ -27,7 +28,8 @@ BsxMemoryPack::~BsxMemoryPack() void BsxMemoryPack::SaveBattery() { - if(_persistFlash) { + if (_persistFlash) + { _console->GetBatteryManager()->SaveBattery(".bs", _data, _dataSize); } } @@ -35,20 +37,24 @@ void BsxMemoryPack::SaveBattery() 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 newData(_data, _data + _dataSize); vector ipsData = IpsPatcher::CreatePatch(_orgData, newData); - VectorInfo data { &ipsData }; + VectorInfo data{&ipsData}; s.Stream(data); - } else { + } + else + { //Apply IPS patch to original data and overwrite the current data vector ipsData; - VectorInfo data { &ipsData }; + VectorInfo data{&ipsData}; s.Stream(data); - if(ipsData.size() > 8) { + if (ipsData.size() > 8) + { vector output; IpsPatcher::PatchBuffer(ipsData, _orgData, output); memcpy(_data, output.data(), _dataSize); @@ -60,27 +66,34 @@ void BsxMemoryPack::ProcessCommand(uint8_t value, uint32_t page) { _command = (_command << 8) | value; - switch(value) { - case 0x00: - case 0xFF: - _enableCsr = false; - _enableEsr = false; - _enableVendorInfo = false; - break; + switch (value) + { + case 0x00: + case 0xFF: + _enableCsr = false; + _enableEsr = false; + _enableVendorInfo = false; + break; - case 0x10: - case 0x40: - _writeByte = true; - break; + case 0x10: + case 0x40: + _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 } } @@ -108,7 +121,8 @@ 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; @@ -116,30 +130,35 @@ BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr) { - if(_offset == 0 && _memPack->_enableEsr) { - switch(addr & 0xFFF) { - case 0x0002: return 0xC0; - case 0x0004: return 0x82; + 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) { - case 0x00: return 0x4d; - case 0x01: return 0x00; - case 0x02: return 0x50; - case 0x03: return 0x00; - case 0x04: return 0x00; - case 0x05: return 0x00; - case 0x06: return 0x10 | _memPack->_calculatedSize; //Memory Pack Type 1 - case 0x07: return 0x00; - default: return 0x00; + switch (addr & 0xFF) + { + case 0x00: return 0x4d; + case 0x01: return 0x00; + case 0x02: return 0x50; + case 0x03: return 0x00; + case 0x04: return 0x00; + case 0x05: return 0x00; + case 0x06: return 0x10 | _memPack->_calculatedSize; //Memory Pack Type 1 + case 0x07: return 0x00; + default: return 0x00; } } @@ -148,11 +167,14 @@ 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); } } diff --git a/Core/BsxMemoryPack.h b/Core/BsxMemoryPack.h index f49ccfc..67292f6 100644 --- a/Core/BsxMemoryPack.h +++ b/Core/BsxMemoryPack.h @@ -35,11 +35,11 @@ public: void ProcessCommand(uint8_t value, uint32_t page); void Reset(); - + vector>& GetMemoryHandlers(); uint8_t* DebugGetMemoryPack(); uint32_t DebugGetMemoryPackSize(); - + class BsxMemoryPackHandler : public RamHandler { BsxMemoryPack* _memPack; diff --git a/Core/BsxSatellaview.cpp b/Core/BsxSatellaview.cpp index c6e5cd7..40d6b73 100644 --- a/Core/BsxSatellaview.cpp +++ b/Core/BsxSatellaview.cpp @@ -21,9 +21,12 @@ 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); } @@ -35,35 +38,37 @@ 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) { - case 0x2188: return _stream[0].GetChannel() & 0xFF; - case 0x2189: return (_stream[0].GetChannel()) >> 8; - case 0x218A: return _stream[0].GetPrefixCount(); - case 0x218B: return _stream[0].GetPrefix(); - case 0x218C: return _stream[0].GetData(); - case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0); - - case 0x218E: return _stream[1].GetChannel() & 0xFF; - case 0x218F: return (_stream[1].GetChannel()) >> 8; - case 0x2190: return _stream[1].GetPrefixCount(); - case 0x2191: return _stream[1].GetPrefix(); - case 0x2192: return _stream[1].GetData(); - case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0); + switch (addr) + { + case 0x2188: return _stream[0].GetChannel() & 0xFF; + case 0x2189: return (_stream[0].GetChannel()) >> 8; + case 0x218A: return _stream[0].GetPrefixCount(); + case 0x218B: return _stream[0].GetPrefix(); + case 0x218C: return _stream[0].GetData(); + case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0); - case 0x2194: return _streamReg; //LED and Stream register - case 0x2195: return 0; //Unknown - case 0x2196: return 0x10; //Satellaview status - case 0x2197: return _extOutput; //Soundlink / EXT output - case 0x2198: return 0x80; //Serial IO (Serial number) - case 0x2199: return 0x01; //Serial IO (???) - case 0x219A: return 0x10; //Unknown + case 0x218E: return _stream[1].GetChannel() & 0xFF; + case 0x218F: return (_stream[1].GetChannel()) >> 8; + case 0x2190: return _stream[1].GetPrefixCount(); + case 0x2191: return _stream[1].GetPrefix(); + case 0x2192: return _stream[1].GetData(); + case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0); + + case 0x2194: return _streamReg; //LED and Stream register + case 0x2195: return 0; //Unknown + case 0x2196: return 0x10; //Satellaview status + case 0x2197: return _extOutput; //Soundlink / EXT output + case 0x2198: return 0x80; //Serial IO (Serial number) + case 0x2199: return 0x01; //Serial IO (???) + case 0x219A: return 0x10; //Unknown } - } - + } + //Use regular B-bus handler for everything else return _bBusHandler->Read(addr); } @@ -71,25 +76,39 @@ 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); } @@ -97,13 +116,16 @@ 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; } @@ -111,7 +133,9 @@ void BsxSatellaview::ProcessClocks() } _prevMasterClock = _memoryManager->GetMasterClock() - gap; - } else { + } + else + { _prevMasterClock = _memoryManager->GetMasterClock(); } } @@ -128,7 +152,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) diff --git a/Core/BsxSatellaview.h b/Core/BsxSatellaview.h index 79548b2..72a5b9c 100644 --- a/Core/BsxSatellaview.h +++ b/Core/BsxSatellaview.h @@ -24,7 +24,7 @@ private: void ProcessClocks(); public: - BsxSatellaview(Console* console, IMemoryHandler *bBusHandler); + BsxSatellaview(Console* console, IMemoryHandler* bBusHandler); void Reset(); @@ -35,4 +35,4 @@ public: AddressInfo GetAbsoluteAddress(uint32_t address) override; void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/BsxStream.cpp b/Core/BsxStream.cpp index b7f9f3c..c4b1aeb 100644 --- a/Core/BsxStream.cpp +++ b/Core/BsxStream.cpp @@ -53,12 +53,15 @@ 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++; } } @@ -80,18 +83,23 @@ 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; } } @@ -104,19 +112,24 @@ 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(); } } @@ -126,19 +139,23 @@ 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; } @@ -151,15 +168,20 @@ 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); @@ -167,7 +189,8 @@ uint8_t BsxStream::GetData() } _fileOffset++; - if(_fileOffset % 22 == 0) { + if (_fileOffset % 22 == 0) + { //Finished reading current packet _dataQueueLength--; } @@ -179,7 +202,8 @@ uint8_t BsxStream::GetData() uint8_t BsxStream::GetStatus(bool reset) { uint8_t status = _status; - if(reset) { + if (reset) + { _status = 0; } return status; @@ -187,7 +211,8 @@ 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; @@ -195,7 +220,8 @@ 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); @@ -215,7 +241,8 @@ 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); @@ -230,30 +257,32 @@ void BsxStream::InitTimeStruct() uint8_t BsxStream::GetTime() { - if(_fileOffset == 0) { + if (_fileOffset == 0) + { InitTimeStruct(); } - 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) - case 3: return 0x00; - case 4: return 0x10; - case 5: return 0x01; //Must be 0x01 - case 6: return 0x01; //Amount of packets (1) - case 7: return 0x00; //Offset (24-bit) - case 8: return 0x00; - case 9: return 0x00; - case 10: return _tm.tm_sec; - case 11: return _tm.tm_min; - case 12: return _tm.tm_hour; - case 13: return _tm.tm_wday; - case 14: return _tm.tm_mday; - case 15: return _tm.tm_mon; - case 16: return _tm.tm_year >> 0; - case 17: return _tm.tm_year >> 8; - default: return 0x00; + 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) + case 3: return 0x00; + case 4: return 0x10; + case 5: return 0x01; //Must be 0x01 + case 6: return 0x01; //Amount of packets (1) + case 7: return 0x00; //Offset (24-bit) + case 8: return 0x00; + case 9: return 0x00; + case 10: return _tm.tm_sec; + case 11: return _tm.tm_min; + case 12: return _tm.tm_hour; + case 13: return _tm.tm_wday; + case 14: return _tm.tm_mday; + case 15: return _tm.tm_mon; + case 16: return _tm.tm_year >> 0; + case 17: return _tm.tm_year >> 8; + default: return 0x00; } } @@ -261,14 +290,17 @@ 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); } diff --git a/Core/CallstackManager.cpp b/Core/CallstackManager.cpp index 19df7d7..f87b616 100644 --- a/Core/CallstackManager.cpp +++ b/Core/CallstackManager.cpp @@ -14,9 +14,11 @@ 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(); } @@ -36,7 +38,8 @@ 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; } @@ -46,14 +49,18 @@ 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(); } @@ -61,18 +68,21 @@ 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++; } @@ -82,7 +92,8 @@ 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; diff --git a/Core/CallstackManager.h b/Core/CallstackManager.h index fb15e4d..3189979 100644 --- a/Core/CallstackManager.h +++ b/Core/CallstackManager.h @@ -16,10 +16,11 @@ 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(); -}; \ No newline at end of file +}; diff --git a/Core/CheatManager.cpp b/Core/CheatManager.cpp index 73fdbf7..5e9211e 100644 --- a/Core/CheatManager.cpp +++ b/Core/CheatManager.cpp @@ -17,11 +17,13 @@ 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; @@ -36,15 +38,21 @@ void CheatManager::SetCheats(vector 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"); } @@ -55,7 +63,8 @@ void CheatManager::SetCheats(uint32_t codes[], uint32_t length) { vector 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; @@ -75,7 +84,8 @@ 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 @@ -86,18 +96,22 @@ void CheatManager::ClearCheats(bool showMessage) void CheatManager::AddStringCheat(string code) { static string _convertTable = "DF4709156BC8A23E"; - + auto lock = _console->AcquireLock(); - + 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; } @@ -119,9 +133,13 @@ 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; } @@ -138,4 +156,4 @@ void CheatManager::AddStringCheat(string code) vector CheatManager::GetCheats() { return _cheats; -} \ No newline at end of file +} diff --git a/Core/CheatManager.h b/Core/CheatManager.h index ce2fd6a..0d0226a 100644 --- a/Core/CheatManager.h +++ b/Core/CheatManager.h @@ -17,7 +17,7 @@ private: bool _bankHasCheats[0x100] = {}; vector _cheats; unordered_map _cheatsByAddress; - + void AddCheat(CheatCode code); public: @@ -31,14 +31,16 @@ public: vector 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; } } diff --git a/Core/ClientConnectionData.h b/Core/ClientConnectionData.h index 0df67f0..9894611 100644 --- a/Core/ClientConnectionData.h +++ b/Core/ClientConnectionData.h @@ -11,7 +11,9 @@ 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) @@ -21,4 +23,4 @@ public: ~ClientConnectionData() { } -}; \ No newline at end of file +}; diff --git a/Core/CodeDataLogger.cpp b/Core/CodeDataLogger.cpp index 6c37319..65aec63 100644 --- a/Core/CodeDataLogger.cpp +++ b/Core/CodeDataLogger.cpp @@ -30,29 +30,37 @@ 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 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); } CalculateStats(); - + return true; } } @@ -62,7 +70,8 @@ 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); @@ -80,10 +89,14 @@ 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++; } } @@ -94,15 +107,24 @@ 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; } } @@ -147,25 +169,31 @@ 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); } @@ -177,24 +205,32 @@ 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) { - romBuffer[i] = 0; - } - } - } else if(flag == CdlStripOption::StripUsed) { - 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; } } } -} \ No newline at end of file + else if (flag == CdlStripOption::StripUsed) + { + for (uint32_t i = 0; i < _prgSize; i++) + { + if (_cdlData[i] != 0) + { + romBuffer[i] = 0; + } + } + } +} diff --git a/Core/CodeDataLogger.h b/Core/CodeDataLogger.h index b680c78..7eb90bc 100644 --- a/Core/CodeDataLogger.h +++ b/Core/CodeDataLogger.h @@ -10,7 +10,7 @@ private: uint32_t _prgSize = 0; uint32_t _codeSize = 0; uint32_t _dataSize = 0; - + void CalculateStats(); public: @@ -34,10 +34,10 @@ 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); void StripData(uint8_t* romBuffer, CdlStripOption flag); -}; \ No newline at end of file +}; diff --git a/Core/Console.cpp b/Core/Console.cpp index 5941e51..68bb04b 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -82,7 +82,7 @@ void Console::Release() _videoDecoder->StopThread(); _videoRenderer->StopThread(); - + _videoDecoder.reset(); _videoRenderer.reset(); _debugHud.reset(); @@ -97,13 +97,18 @@ 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(); } } @@ -111,10 +116,11 @@ void Console::RunFrame() void Console::Run() { - if(!_cpu) { + if (!_cpu) + { return; } - + auto emulationLock = _emulationLock.AcquireSafe(); auto lock = _runLock.AcquireSafe(); @@ -134,14 +140,20 @@ 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(); @@ -150,16 +162,19 @@ 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(); } @@ -174,10 +189,13 @@ 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; } @@ -194,7 +212,8 @@ 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(); @@ -204,9 +223,10 @@ void Console::RunFrameWithRunAhead() //Run one frame normally (with audio/video output) RunFrame(); _rewindManager->ProcessEndOfFrame(); - + bool wasReset = ProcessSystemActions(); - if(!wasReset) { + if (!wasReset) + { //Load the state we saved earlier _isRunAheadFrame = true; Deserialize(runAheadState, SaveStateManager::FileFormatVersion, false); @@ -218,27 +238,33 @@ 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); @@ -264,7 +290,8 @@ void Console::RunSingleFrame() RunFrame(); _cart->RunCoprocessors(); - if(_cart->GetCoprocessor()) { + if (_cart->GetCoprocessor()) + { _cart->GetCoprocessor()->ProcessEndOfFrame(); } @@ -278,24 +305,28 @@ void Console::Stop(bool sendNotification) _notificationManager->SendNotification(ConsoleNotificationType::BeforeGameUnload); shared_ptr 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); } @@ -321,7 +352,8 @@ void Console::Stop(bool sendNotification) _soundMixer->StopAudio(true); - if(sendNotification) { + if (sendNotification) + { _notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped); } } @@ -347,28 +379,34 @@ 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); } - _runLock.Release(); + _runLock.Release(); _lockCounter--; } void Console::ReloadRom(bool forPowerCycle) { shared_ptr cart = _cart; - if(cart) { + if (cart) + { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->Run(); } @@ -386,27 +424,32 @@ 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 cart = forPowerCycle ? _cart : BaseCartridge::CreateCartridge(this, romFile, patchFile); - if(cart) { + if (cart) + { bool debuggerActive = _debugger != nullptr; - if(stopRom) { + if (stopRom) + { KeyManager::UpdateDevices(); Stop(false); } _cheatManager->ClearCheats(false); - + _cart = cart; - + auto lock = _debuggerLock.AcquireSafe(); - if(_debugger) { + if (_debugger) + { //Reset debugger if it was running before _debugger->Release(); _debugger.reset(); @@ -425,10 +468,13 @@ 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(); } @@ -436,16 +482,20 @@ 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(); } @@ -456,26 +506,31 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _notificationManager->RegisterNotificationListener(_rewindManager); _controlManager->UpdateControlDevices(); - + UpdateRegion(); _notificationManager->SendNotification(ConsoleNotificationType::GameLoaded, (void*)forPowerCycle); _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()); } @@ -486,18 +541,24 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, RomInfo Console::GetRomInfo() { shared_ptr 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(); } } @@ -519,12 +580,16 @@ 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; + default: + case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; + break; + case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; + break; } _masterClockRate = _region == ConsoleRegion::Pal ? 21281370 : 21477270; @@ -532,12 +597,18 @@ 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; } } @@ -547,17 +618,28 @@ 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) { - default: - case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 16.6666666666666666667 : 16.63926405550947; break; - case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; break; + } + 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; } } frameDelay /= (emulationSpeed / 100.0); @@ -587,13 +669,19 @@ void Console::CopyRewindData(shared_ptr sourceConsole) void Console::PauseOnNextFrame() { shared_ptr 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; } @@ -602,13 +690,19 @@ void Console::PauseOnNextFrame() void Console::Pause() { shared_ptr 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; } } @@ -616,9 +710,12 @@ void Console::Pause() void Console::Resume() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->Run(); - } else { + } + else + { _paused = false; } } @@ -626,9 +723,12 @@ void Console::Resume() bool Console::IsPaused() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { return debugger->IsExecutionStopped(); - } else { + } + else + { return _paused; } } @@ -643,14 +743,16 @@ 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(30)); } PlatformUtilities::DisableScreensaver(); _runLock.Acquire(); - if(!_stopFlag) { + if (!_stopFlag) + { _notificationManager->SendNotification(ConsoleNotificationType::GameResumed); } } @@ -663,7 +765,8 @@ ConsoleLock Console::AcquireLock() void Console::Lock() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); } @@ -674,7 +777,8 @@ void Console::Lock() void Console::Unlock() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(true); } @@ -689,18 +793,24 @@ 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; - if(debugger) { - while(debugger->HasBreakRequest()) {} + if (debugger) + { + while (debugger->HasBreakRequest()) + { + } } _threadPaused = false; @@ -709,12 +819,13 @@ 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()); @@ -723,22 +834,26 @@ 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()); @@ -747,10 +862,13 @@ 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()); } @@ -860,11 +978,13 @@ shared_ptr Console::GetMsu1() shared_ptr Console::GetDebugger(bool autoStart) { shared_ptr 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; } @@ -908,37 +1028,44 @@ bool Console::IsRunAheadFrame() uint32_t Console::GetFrameCount() { shared_ptr 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; return ppu ? ppu->GetFrameCount() : 0; } } -template +template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessInterrupt(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); } } diff --git a/Core/Console.h b/Core/Console.h index acfd904..a2d5d2b 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -53,7 +53,7 @@ private: shared_ptr _internalRegisters; shared_ptr _controlManager; shared_ptr _dmaController; - + shared_ptr _msu1; shared_ptr _debugger; @@ -73,7 +73,7 @@ private: shared_ptr _spcHud; thread::id _emulationThreadId; - + atomic _lockCounter; SimpleLock _runLock; SimpleLock _emulationLock; @@ -124,7 +124,7 @@ public: void PowerCycle(); void PauseOnNextFrame(); - + void Pause(); void Resume(); bool IsPaused(); @@ -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 GetSoundMixer(); shared_ptr GetVideoRenderer(); @@ -172,72 +172,84 @@ public: bool IsDebugging(); thread::id GetEmulationThreadId(); - + bool IsRunning(); bool IsRunAheadFrame(); - uint32_t GetFrameCount(); + uint32_t GetFrameCount(); double GetFps(); void CopyRewindData(shared_ptr sourceConsole); - template __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) + template + __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessMemoryRead(addr, value, opType); } } - template __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) + template + __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessMemoryWrite(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 __forceinline void ProcessPpuCycle() + + template + __forceinline void ProcessPpuCycle() { - if(_debugger) { + if (_debugger) + { _debugger->ProcessPpuCycle(); } } __forceinline void DebugLog(string log) { - if(_debugger) { + if (_debugger) + { _debugger->Log(log); } } - template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); + template + void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type); void BreakImmediately(BreakSource source); }; diff --git a/Core/ConsoleLock.cpp b/Core/ConsoleLock.cpp index 783fc31..800be1d 100644 --- a/Core/ConsoleLock.cpp +++ b/Core/ConsoleLock.cpp @@ -3,7 +3,7 @@ #include "Console.h" #include "Debugger.h" -ConsoleLock::ConsoleLock(Console *console) +ConsoleLock::ConsoleLock(Console* console) { _console = console; _console->Lock(); diff --git a/Core/ConsoleLock.h b/Core/ConsoleLock.h index fd79c3d..94dedb4 100644 --- a/Core/ConsoleLock.h +++ b/Core/ConsoleLock.h @@ -7,9 +7,9 @@ class Debugger; class ConsoleLock { private: - Console *_console = nullptr; + Console* _console = nullptr; public: - ConsoleLock(Console *console); + ConsoleLock(Console* console); ~ConsoleLock(); -}; \ No newline at end of file +}; diff --git a/Core/ControlDeviceState.h b/Core/ControlDeviceState.h index bcc392e..7c17098 100644 --- a/Core/ControlDeviceState.h +++ b/Core/ControlDeviceState.h @@ -7,7 +7,7 @@ struct ControlDeviceState { vector State; - bool operator!=(ControlDeviceState &other) + bool operator!=(ControlDeviceState& other) { return State.size() != other.State.size() || memcmp(State.data(), other.State.data(), State.size()) != 0; } @@ -17,4 +17,4 @@ struct ControllerData { ControllerType Type; ControlDeviceState State; -}; \ No newline at end of file +}; diff --git a/Core/ControlManager.cpp b/Core/ControlManager.cpp index 8aa15b0..9e3d9b8 100644 --- a/Core/ControlManager.cpp +++ b/Core/ControlManager.cpp @@ -37,7 +37,7 @@ void ControlManager::RegisterInputProvider(IInputProvider* provider) void ControlManager::UnregisterInputProvider(IInputProvider* provider) { auto lock = _deviceLock.AcquireSafe(); - vector &vec = _inputProviders; + vector& 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 &vec = _inputRecorders; + vector& vec = _inputRecorders; vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end()); } @@ -59,12 +59,16 @@ vector ControlManager::GetPortStates() auto lock = _deviceLock.AcquireSafe(); vector states; - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { shared_ptr 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; @@ -79,8 +83,13 @@ shared_ptr ControlManager::GetControlDevice(uint8_t port) { auto lock = _deviceLock.AcquireSafe(); - auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), [port](const shared_ptr control) { return control->GetPort() == port; }); - if(result != _controlDevices.end()) { + auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), + [port](const shared_ptr control) + { + return control->GetPort() == port; + }); + if (result != _controlDevices.end()) + { return *result; } return nullptr; @@ -101,35 +110,46 @@ ControllerType ControlManager::GetControllerType(uint8_t port) return _console->GetSettings()->GetInputConfig().Controllers[port].Type; } -shared_ptr ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, Console* console) +shared_ptr ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, + Console* console) { shared_ptr device; - + InputConfig cfg = console->GetSettings()->GetInputConfig(); - 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; + 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; } - + return device; } 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 device = CreateControllerDevice(GetControllerType(i), i, _console); - if(device) { + if (device) + { RegisterControlDevice(device); } } @@ -143,13 +163,16 @@ void ControlManager::UpdateInputState() auto lock = _deviceLock.AcquireSafe(); //string log = "F: " + std::to_string(_console->GetPpu()->GetFrameCount()) + " C:" + std::to_string(_pollCounter) + " "; - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& 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; } } @@ -159,12 +182,15 @@ void ControlManager::UpdateInputState() } shared_ptr 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); } } @@ -187,7 +213,8 @@ 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 &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { value |= device->ReadRam(addr); } @@ -196,21 +223,25 @@ uint8_t ControlManager::Read(uint16_t addr) void ControlManager::Write(uint16_t addr, uint8_t value) { - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& 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 &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { s.Stream(device.get()); } } diff --git a/Core/ControlManager.h b/Core/ControlManager.h index 7ee212f..675abfe 100644 --- a/Core/ControlManager.h +++ b/Core/ControlManager.h @@ -19,7 +19,7 @@ class ControlManager : public ISerializable private: vector _inputRecorders; vector _inputProviders; - + uint32_t _pollCounter; uint32_t _inputConfigVersion; @@ -54,11 +54,11 @@ public: SystemActionManager* GetSystemActionManager(); shared_ptr GetControlDevice(uint8_t port); vector> GetControlDevices(); - + static shared_ptr CreateControllerDevice(ControllerType type, uint8_t port, Console* console); uint8_t Read(uint16_t addr); void Write(uint16_t addr, uint8_t value); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/Cpu.Instructions.h b/Core/Cpu.Instructions.h index ba14506..302831b 100644 --- a/Core/Cpu.Instructions.h +++ b/Core/Cpu.Instructions.h @@ -4,28 +4,36 @@ 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); } @@ -35,35 +43,43 @@ 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); } @@ -72,9 +88,12 @@ void Cpu::Add16(uint16_t value) void Cpu::ADC() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { Add8(GetByteValue()); - } else { + } + else + { Add16(GetWordValue()); } } @@ -82,28 +101,36 @@ 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); } @@ -113,35 +140,43 @@ 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); } @@ -150,9 +185,12 @@ void Cpu::Sub16(uint16_t value) void Cpu::SBC() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { Sub8(~GetByteValue()); - } else { + } + else + { Sub16(~GetWordValue()); } } @@ -213,10 +251,12 @@ 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(); } @@ -273,7 +313,8 @@ 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; @@ -323,19 +364,22 @@ void Cpu::INC_Acc() SetRegister(_state.A, _state.A + 1, CheckFlag(ProcFlags::MemoryMode8)); } -void Cpu::IncDecReg(uint16_t ®, 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(); @@ -348,20 +392,29 @@ 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); } @@ -423,10 +476,13 @@ 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(); @@ -461,13 +517,15 @@ 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); @@ -476,7 +534,9 @@ 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); @@ -504,27 +564,36 @@ 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); } } @@ -532,48 +601,64 @@ void Cpu::ORA() /**************** Shift operations *****************/ -template T Cpu::ShiftLeft(T value) +template +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 T Cpu::RollLeft(T value) +template +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 T Cpu::ShiftRight(T value) +template +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 T Cpu::RollRight(T value) +template +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); @@ -582,20 +667,26 @@ template 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)_state.A)); - } else { + } + else + { _state.A = ShiftLeft(_state.A); } } void Cpu::ASL() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, ShiftLeft(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, ShiftLeft(value)); @@ -604,20 +695,26 @@ void Cpu::ASL() void Cpu::LSR_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | ShiftRight((uint8_t)_state.A); - } else { + } + else + { _state.A = ShiftRight(_state.A); } } void Cpu::LSR() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, ShiftRight(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, ShiftRight(value)); @@ -626,20 +723,26 @@ void Cpu::LSR() void Cpu::ROL_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | RollLeft((uint8_t)_state.A); - } else { + } + else + { _state.A = RollLeft(_state.A); } } void Cpu::ROL() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, RollLeft(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, RollLeft(value)); @@ -648,20 +751,26 @@ void Cpu::ROL() void Cpu::ROR_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | RollRight((uint8_t)_state.A); - } else { + } + else + { _state.A = RollRight(_state.A); } } void Cpu::ROR() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, RollRight(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, RollRight(value)); @@ -685,14 +794,16 @@ 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; } @@ -712,14 +823,16 @@ 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; } @@ -793,9 +906,12 @@ 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()); } } @@ -844,19 +960,25 @@ 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 ®, 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); } } @@ -864,20 +986,26 @@ void Cpu::PullRegister(uint16_t ®, bool eightBitMode) /********************* Store/load operations **********************/ -void Cpu::LoadRegister(uint16_t ®, 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); } } @@ -927,26 +1055,36 @@ void Cpu::STZ() /******************* Bit test operations ********************/ -template void Cpu::TestBits(T value, bool alterZeroFlagOnly) +template +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); } } @@ -954,16 +1092,20 @@ template void Cpu::TestBits(T value, bool alterZeroFlagOnly) void Cpu::BIT() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { TestBits(GetByteValue(), _immediateMode); - } else { + } + else + { TestBits(GetWordValue(), _immediateMode); } } void Cpu::TRB() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); TestBits(value, true); @@ -971,7 +1113,9 @@ void Cpu::TRB() Idle(); Write(_operand, value); - } else { + } + else + { uint16_t value = GetWordValue(); TestBits(value, true); @@ -984,7 +1128,8 @@ void Cpu::TRB() void Cpu::TSB() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); TestBits(value, true); @@ -992,7 +1137,9 @@ void Cpu::TSB() Idle(); Write(_operand, value); - } else { + } + else + { uint16_t value = GetWordValue(); TestBits(value, true); @@ -1076,14 +1223,18 @@ 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); } @@ -1129,7 +1280,8 @@ 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(); } } @@ -1138,7 +1290,8 @@ 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(); } } @@ -1192,7 +1345,8 @@ 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(); } @@ -1232,8 +1386,9 @@ 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(); } } @@ -1268,7 +1423,7 @@ void Cpu::AddrMode_ImmX() void Cpu::AddrMode_ImmM() { - _immediateMode = true; + _immediateMode = true; _operand = CheckFlag(ProcFlags::MemoryMode8) ? ReadOperandByte() : ReadOperandWord(); } diff --git a/Core/Cpu.Shared.h b/Core/Cpu.Shared.h index 309da55..e3a8190 100644 --- a/Core/Cpu.Shared.h +++ b/Core/Cpu.Shared.h @@ -39,263 +39,761 @@ void Cpu::Reset() void Cpu::RunOp() { - switch(GetOpCode()) { - case 0x00: AddrMode_Imm8(); BRK(); break; - case 0x01: AddrMode_DirIdxIndX(); ORA(); break; - case 0x02: AddrMode_Imm8(); COP(); break; - case 0x03: AddrMode_StkRel(); ORA(); break; - case 0x04: AddrMode_Dir(); TSB(); break; - case 0x05: AddrMode_Dir(); ORA(); break; - case 0x06: AddrMode_Dir(); ASL(); break; - case 0x07: AddrMode_DirIndLng(); ORA(); break; - case 0x08: PHP(); break; - case 0x09: AddrMode_ImmM(); ORA(); break; - case 0x0A: AddrMode_Acc(); ASL_Acc(); break; - case 0x0B: PHD(); break; - case 0x0C: AddrMode_Abs(); TSB(); break; - case 0x0D: AddrMode_Abs(); ORA(); break; - case 0x0E: AddrMode_Abs(); ASL(); break; - case 0x0F: AddrMode_AbsLng(); ORA(); break; - case 0x10: AddrMode_Rel(); BPL(); break; - case 0x11: AddrMode_DirIndIdxY(false); ORA(); break; - case 0x12: AddrMode_DirInd(); ORA(); break; - case 0x13: AddrMode_StkRelIndIdxY(); ORA(); break; - case 0x14: AddrMode_Dir(); TRB(); break; - case 0x15: AddrMode_DirIdxX(); ORA(); break; - case 0x16: AddrMode_DirIdxX(); ASL(); break; - case 0x17: AddrMode_DirIndLngIdxY(); ORA(); break; - case 0x18: AddrMode_Imp(); CLC(); break; - case 0x19: AddrMode_AbsIdxY(false); ORA(); break; - case 0x1A: AddrMode_Acc(); INC_Acc(); break; - case 0x1B: AddrMode_Imp(); TCS(); break; - case 0x1C: AddrMode_Abs(); TRB(); break; - case 0x1D: AddrMode_AbsIdxX(false); ORA(); break; - case 0x1E: AddrMode_AbsIdxX(true); ASL(); break; - case 0x1F: AddrMode_AbsLngIdxX(); ORA(); break; - case 0x20: AddrMode_AbsJmp(); Idle(); JSR(); break; - case 0x21: AddrMode_DirIdxIndX(); AND(); break; - case 0x22: AddrMode_AbsLngJmp(); JSL(); break; - case 0x23: AddrMode_StkRel(); AND(); break; - case 0x24: AddrMode_Dir(); BIT(); break; - case 0x25: AddrMode_Dir(); AND(); break; - case 0x26: AddrMode_Dir(); ROL(); break; - case 0x27: AddrMode_DirIndLng(); AND(); break; - case 0x28: PLP(); break; - case 0x29: AddrMode_ImmM(); AND(); break; - case 0x2A: AddrMode_Acc(); ROL_Acc(); break; - case 0x2B: PLD(); break; - case 0x2C: AddrMode_Abs(); BIT(); break; - case 0x2D: AddrMode_Abs(); AND(); break; - case 0x2E: AddrMode_Abs(); ROL(); break; - case 0x2F: AddrMode_AbsLng(); AND(); break; - case 0x30: AddrMode_Rel(); BMI(); break; - case 0x31: AddrMode_DirIndIdxY(false); AND(); break; - case 0x32: AddrMode_DirInd(); AND(); break; - case 0x33: AddrMode_StkRelIndIdxY(); AND(); break; - case 0x34: AddrMode_DirIdxX(); BIT(); break; - case 0x35: AddrMode_DirIdxX(); AND(); break; - case 0x36: AddrMode_DirIdxX(); ROL(); break; - case 0x37: AddrMode_DirIndLngIdxY(); AND(); break; - case 0x38: AddrMode_Imp(); SEC(); break; - case 0x39: AddrMode_AbsIdxY(false); AND(); break; - case 0x3A: AddrMode_Acc(); DEC_Acc(); break; - case 0x3B: AddrMode_Imp(); TSC(); break; - case 0x3C: AddrMode_AbsIdxX(false); BIT(); break; - case 0x3D: AddrMode_AbsIdxX(false); AND(); break; - case 0x3E: AddrMode_AbsIdxX(true); ROL(); break; - case 0x3F: AddrMode_AbsLngIdxX(); AND(); break; - case 0x40: RTI(); break; - case 0x41: AddrMode_DirIdxIndX(); EOR(); break; - case 0x42: AddrMode_Imm8(); WDM(); break; - case 0x43: AddrMode_StkRel(); EOR(); break; - case 0x44: AddrMode_BlkMov(); MVP(); break; - case 0x45: AddrMode_Dir(); EOR(); break; - case 0x46: AddrMode_Dir(); LSR(); break; - case 0x47: AddrMode_DirIndLng(); EOR(); break; - case 0x48: PHA(); break; - case 0x49: AddrMode_ImmM(); EOR(); break; - case 0x4A: AddrMode_Acc(); LSR_Acc(); break; - case 0x4B: PHK(); break; - case 0x4C: AddrMode_AbsJmp(); JMP(); break; - case 0x4D: AddrMode_Abs(); EOR(); break; - case 0x4E: AddrMode_Abs(); LSR(); break; - case 0x4F: AddrMode_AbsLng(); EOR(); break; - case 0x50: AddrMode_Rel(); BVC(); break; - case 0x51: AddrMode_DirIndIdxY(false); EOR(); break; - case 0x52: AddrMode_DirInd(); EOR(); break; - case 0x53: AddrMode_StkRelIndIdxY(); EOR(); break; - case 0x54: AddrMode_BlkMov(); MVN(); break; - case 0x55: AddrMode_DirIdxX(); EOR(); break; - case 0x56: AddrMode_DirIdxX(); LSR(); break; - case 0x57: AddrMode_DirIndLngIdxY(); EOR(); break; - case 0x58: AddrMode_Imp(); CLI(); break; - case 0x59: AddrMode_AbsIdxY(false); EOR(); break; - case 0x5A: PHY(); break; - case 0x5B: AddrMode_Imp(); TCD(); break; - case 0x5C: AddrMode_AbsLngJmp(); JML(); break; - case 0x5D: AddrMode_AbsIdxX(false); EOR(); break; - case 0x5E: AddrMode_AbsIdxX(true); LSR(); break; - case 0x5F: AddrMode_AbsLngIdxX(); EOR(); break; - case 0x60: RTS(); break; - case 0x61: AddrMode_DirIdxIndX(); ADC(); break; - case 0x62: AddrMode_RelLng(); PER(); break; - case 0x63: AddrMode_StkRel(); ADC(); break; - case 0x64: AddrMode_Dir(); STZ(); break; - case 0x65: AddrMode_Dir(); ADC(); break; - case 0x66: AddrMode_Dir(); ROR(); break; - case 0x67: AddrMode_DirIndLng(); ADC(); break; - case 0x68: PLA(); break; - case 0x69: AddrMode_ImmM(); ADC(); break; - case 0x6A: AddrMode_Acc(); ROR_Acc(); break; - case 0x6B: RTL(); break; - case 0x6C: AddrMode_AbsInd(); JMP(); break; - case 0x6D: AddrMode_Abs(); ADC(); break; - case 0x6E: AddrMode_Abs(); ROR(); break; - case 0x6F: AddrMode_AbsLng(); ADC(); break; - case 0x70: AddrMode_Rel(); BVS(); break; - case 0x71: AddrMode_DirIndIdxY(false); ADC(); break; - case 0x72: AddrMode_DirInd(); ADC(); break; - case 0x73: AddrMode_StkRelIndIdxY(); ADC(); break; - case 0x74: AddrMode_DirIdxX(); STZ(); break; - case 0x75: AddrMode_DirIdxX(); ADC(); break; - case 0x76: AddrMode_DirIdxX(); ROR(); break; - case 0x77: AddrMode_DirIndLngIdxY(); ADC(); break; - case 0x78: AddrMode_Imp(); SEI(); break; - case 0x79: AddrMode_AbsIdxY(false); ADC(); break; - case 0x7A: PLY(); break; - case 0x7B: AddrMode_Imp(); TDC(); break; - case 0x7C: AddrMode_AbsIdxXInd(); JMP(); break; - case 0x7D: AddrMode_AbsIdxX(false); ADC(); break; - case 0x7E: AddrMode_AbsIdxX(true); ROR(); break; - case 0x7F: AddrMode_AbsLngIdxX(); ADC(); break; - case 0x80: AddrMode_Rel(); BRA(); break; - case 0x81: AddrMode_DirIdxIndX(); STA(); break; - case 0x82: AddrMode_RelLng(); BRL(); break; - case 0x83: AddrMode_StkRel(); STA(); break; - case 0x84: AddrMode_Dir(); STY(); break; - case 0x85: AddrMode_Dir(); STA(); break; - case 0x86: AddrMode_Dir(); STX(); break; - case 0x87: AddrMode_DirIndLng(); STA(); break; - case 0x88: AddrMode_Imp(); DEY(); break; - case 0x89: AddrMode_ImmM(); BIT(); break; - case 0x8A: AddrMode_Imp(); TXA(); break; - case 0x8B: PHB(); break; - case 0x8C: AddrMode_Abs(); STY(); break; - case 0x8D: AddrMode_Abs(); STA(); break; - case 0x8E: AddrMode_Abs(); STX(); break; - case 0x8F: AddrMode_AbsLng(); STA(); break; - case 0x90: AddrMode_Rel(); BCC(); break; - case 0x91: AddrMode_DirIndIdxY(true); STA(); break; - case 0x92: AddrMode_DirInd(); STA(); break; - case 0x93: AddrMode_StkRelIndIdxY(); STA(); break; - case 0x94: AddrMode_DirIdxX(); STY(); break; - case 0x95: AddrMode_DirIdxX(); STA(); break; - case 0x96: AddrMode_DirIdxY(); STX(); break; - case 0x97: AddrMode_DirIndLngIdxY(); STA(); break; - case 0x98: AddrMode_Imp(); TYA(); break; - case 0x99: AddrMode_AbsIdxY(true); STA(); break; - case 0x9A: AddrMode_Imp(); TXS(); break; - case 0x9B: AddrMode_Imp(); TXY(); break; - case 0x9C: AddrMode_Abs(); STZ(); break; - case 0x9D: AddrMode_AbsIdxX(true); STA(); break; - case 0x9E: AddrMode_AbsIdxX(true); STZ(); break; - case 0x9F: AddrMode_AbsLngIdxX(); STA(); break; - case 0xA0: AddrMode_ImmX(); LDY(); break; - case 0xA1: AddrMode_DirIdxIndX(); LDA(); break; - case 0xA2: AddrMode_ImmX(); LDX(); break; - case 0xA3: AddrMode_StkRel(); LDA(); break; - case 0xA4: AddrMode_Dir(); LDY(); break; - case 0xA5: AddrMode_Dir(); LDA(); break; - case 0xA6: AddrMode_Dir(); LDX(); break; - case 0xA7: AddrMode_DirIndLng(); LDA(); break; - case 0xA8: AddrMode_Imp(); TAY(); break; - case 0xA9: AddrMode_ImmM(); LDA(); break; - case 0xAA: AddrMode_Imp(); TAX(); break; - case 0xAB: PLB(); break; - case 0xAC: AddrMode_Abs(); LDY(); break; - case 0xAD: AddrMode_Abs(); LDA(); break; - case 0xAE: AddrMode_Abs(); LDX(); break; - case 0xAF: AddrMode_AbsLng(); LDA(); break; - case 0xB0: AddrMode_Rel(); BCS(); break; - case 0xB1: AddrMode_DirIndIdxY(false); LDA(); break; - case 0xB2: AddrMode_DirInd(); LDA(); break; - case 0xB3: AddrMode_StkRelIndIdxY(); LDA(); break; - case 0xB4: AddrMode_DirIdxX(); LDY(); break; - case 0xB5: AddrMode_DirIdxX(); LDA(); break; - case 0xB6: AddrMode_DirIdxY(); LDX(); break; - case 0xB7: AddrMode_DirIndLngIdxY(); LDA(); break; - case 0xB8: AddrMode_Imp(); CLV(); break; - case 0xB9: AddrMode_AbsIdxY(false); LDA(); break; - case 0xBA: AddrMode_Imp(); TSX(); break; - case 0xBB: AddrMode_Imp(); TYX(); break; - case 0xBC: AddrMode_AbsIdxX(false); LDY(); break; - case 0xBD: AddrMode_AbsIdxX(false); LDA(); break; - case 0xBE: AddrMode_AbsIdxY(false); LDX(); break; - case 0xBF: AddrMode_AbsLngIdxX(); LDA(); break; - case 0xC0: AddrMode_ImmX(); CPY(); break; - case 0xC1: AddrMode_DirIdxIndX(); CMP(); break; - case 0xC2: AddrMode_Imm8(); REP(); break; - case 0xC3: AddrMode_StkRel(); CMP(); break; - case 0xC4: AddrMode_Dir(); CPY(); break; - case 0xC5: AddrMode_Dir(); CMP(); break; - case 0xC6: AddrMode_Dir(); DEC(); break; - case 0xC7: AddrMode_DirIndLng(); CMP(); break; - case 0xC8: AddrMode_Imp(); INY(); break; - case 0xC9: AddrMode_ImmM(); CMP(); break; - case 0xCA: AddrMode_Imp(); DEX(); break; - case 0xCB: AddrMode_Imp(); WAI(); break; - case 0xCC: AddrMode_Abs(); CPY(); break; - case 0xCD: AddrMode_Abs(); CMP(); break; - case 0xCE: AddrMode_Abs(); DEC(); break; - case 0xCF: AddrMode_AbsLng(); CMP(); break; - case 0xD0: AddrMode_Rel(); BNE(); break; - case 0xD1: AddrMode_DirIndIdxY(false); CMP(); break; - case 0xD2: AddrMode_DirInd(); CMP(); break; - case 0xD3: AddrMode_StkRelIndIdxY(); CMP(); break; - case 0xD4: AddrMode_Dir(); PEI(); break; - case 0xD5: AddrMode_DirIdxX(); CMP(); break; - case 0xD6: AddrMode_DirIdxX(); DEC(); break; - case 0xD7: AddrMode_DirIndLngIdxY(); CMP(); break; - case 0xD8: AddrMode_Imp(); CLD(); break; - case 0xD9: AddrMode_AbsIdxY(false); CMP(); break; - case 0xDA: PHX(); break; - case 0xDB: AddrMode_Imp(); STP(); break; - case 0xDC: AddrMode_AbsIndLng(); JML(); break; - case 0xDD: AddrMode_AbsIdxX(false); CMP(); break; - case 0xDE: AddrMode_AbsIdxX(true); DEC(); break; - case 0xDF: AddrMode_AbsLngIdxX(); CMP(); break; - case 0xE0: AddrMode_ImmX(); CPX(); break; - case 0xE1: AddrMode_DirIdxIndX(); SBC(); break; - case 0xE2: AddrMode_Imm8(); SEP(); break; - case 0xE3: AddrMode_StkRel(); SBC(); break; - case 0xE4: AddrMode_Dir(); CPX(); break; - case 0xE5: AddrMode_Dir(); SBC(); break; - case 0xE6: AddrMode_Dir(); INC(); break; - case 0xE7: AddrMode_DirIndLng(); SBC(); break; - case 0xE8: AddrMode_Imp(); INX(); break; - case 0xE9: AddrMode_ImmM(); SBC(); break; - case 0xEA: AddrMode_Imp(); NOP(); break; - case 0xEB: AddrMode_Imp(); XBA(); break; - case 0xEC: AddrMode_Abs(); CPX(); break; - case 0xED: AddrMode_Abs(); SBC(); break; - case 0xEE: AddrMode_Abs(); INC(); break; - case 0xEF: AddrMode_AbsLng(); SBC(); break; - case 0xF0: AddrMode_Rel(); BEQ(); break; - case 0xF1: AddrMode_DirIndIdxY(false); SBC(); break; - case 0xF2: AddrMode_DirInd(); SBC(); break; - case 0xF3: AddrMode_StkRelIndIdxY(); SBC(); break; - case 0xF4: AddrMode_Imm16(); PEA(); break; - case 0xF5: AddrMode_DirIdxX(); SBC(); break; - case 0xF6: AddrMode_DirIdxX(); INC(); break; - case 0xF7: AddrMode_DirIndLngIdxY(); SBC(); break; - case 0xF8: AddrMode_Imp(); SED(); break; - case 0xF9: AddrMode_AbsIdxY(false); SBC(); break; - case 0xFA: PLX(); break; - case 0xFB: AddrMode_Imp(); XCE(); break; - case 0xFC: AddrMode_AbsIdxXInd(); JSR(); break; - case 0xFD: AddrMode_AbsIdxX(false); SBC(); break; - case 0xFE: AddrMode_AbsIdxX(true); INC(); break; - case 0xFF: AddrMode_AbsLngIdxX(); SBC(); break; + switch (GetOpCode()) + { + case 0x00: AddrMode_Imm8(); + BRK(); + break; + case 0x01: AddrMode_DirIdxIndX(); + ORA(); + break; + case 0x02: AddrMode_Imm8(); + COP(); + break; + case 0x03: AddrMode_StkRel(); + ORA(); + break; + case 0x04: AddrMode_Dir(); + TSB(); + break; + case 0x05: AddrMode_Dir(); + ORA(); + break; + case 0x06: AddrMode_Dir(); + ASL(); + break; + case 0x07: AddrMode_DirIndLng(); + ORA(); + break; + case 0x08: PHP(); + break; + case 0x09: AddrMode_ImmM(); + ORA(); + break; + case 0x0A: AddrMode_Acc(); + ASL_Acc(); + break; + case 0x0B: PHD(); + break; + case 0x0C: AddrMode_Abs(); + TSB(); + break; + case 0x0D: AddrMode_Abs(); + ORA(); + break; + case 0x0E: AddrMode_Abs(); + ASL(); + break; + case 0x0F: AddrMode_AbsLng(); + ORA(); + break; + case 0x10: AddrMode_Rel(); + BPL(); + break; + case 0x11: AddrMode_DirIndIdxY(false); + ORA(); + break; + case 0x12: AddrMode_DirInd(); + ORA(); + break; + case 0x13: AddrMode_StkRelIndIdxY(); + ORA(); + break; + case 0x14: AddrMode_Dir(); + TRB(); + break; + case 0x15: AddrMode_DirIdxX(); + ORA(); + break; + case 0x16: AddrMode_DirIdxX(); + ASL(); + break; + case 0x17: AddrMode_DirIndLngIdxY(); + ORA(); + break; + case 0x18: AddrMode_Imp(); + CLC(); + break; + case 0x19: AddrMode_AbsIdxY(false); + ORA(); + break; + case 0x1A: AddrMode_Acc(); + INC_Acc(); + break; + case 0x1B: AddrMode_Imp(); + TCS(); + break; + case 0x1C: AddrMode_Abs(); + TRB(); + break; + case 0x1D: AddrMode_AbsIdxX(false); + ORA(); + break; + case 0x1E: AddrMode_AbsIdxX(true); + ASL(); + break; + case 0x1F: AddrMode_AbsLngIdxX(); + ORA(); + break; + case 0x20: AddrMode_AbsJmp(); + Idle(); + JSR(); + break; + case 0x21: AddrMode_DirIdxIndX(); + AND(); + break; + case 0x22: AddrMode_AbsLngJmp(); + JSL(); + break; + case 0x23: AddrMode_StkRel(); + AND(); + break; + case 0x24: AddrMode_Dir(); + BIT(); + break; + case 0x25: AddrMode_Dir(); + AND(); + break; + case 0x26: AddrMode_Dir(); + ROL(); + break; + case 0x27: AddrMode_DirIndLng(); + AND(); + break; + case 0x28: PLP(); + break; + case 0x29: AddrMode_ImmM(); + AND(); + break; + case 0x2A: AddrMode_Acc(); + ROL_Acc(); + break; + case 0x2B: PLD(); + break; + case 0x2C: AddrMode_Abs(); + BIT(); + break; + case 0x2D: AddrMode_Abs(); + AND(); + break; + case 0x2E: AddrMode_Abs(); + ROL(); + break; + case 0x2F: AddrMode_AbsLng(); + AND(); + break; + case 0x30: AddrMode_Rel(); + BMI(); + break; + case 0x31: AddrMode_DirIndIdxY(false); + AND(); + break; + case 0x32: AddrMode_DirInd(); + AND(); + break; + case 0x33: AddrMode_StkRelIndIdxY(); + AND(); + break; + case 0x34: AddrMode_DirIdxX(); + BIT(); + break; + case 0x35: AddrMode_DirIdxX(); + AND(); + break; + case 0x36: AddrMode_DirIdxX(); + ROL(); + break; + case 0x37: AddrMode_DirIndLngIdxY(); + AND(); + break; + case 0x38: AddrMode_Imp(); + SEC(); + break; + case 0x39: AddrMode_AbsIdxY(false); + AND(); + break; + case 0x3A: AddrMode_Acc(); + DEC_Acc(); + break; + case 0x3B: AddrMode_Imp(); + TSC(); + break; + case 0x3C: AddrMode_AbsIdxX(false); + BIT(); + break; + case 0x3D: AddrMode_AbsIdxX(false); + AND(); + break; + case 0x3E: AddrMode_AbsIdxX(true); + ROL(); + break; + case 0x3F: AddrMode_AbsLngIdxX(); + AND(); + break; + case 0x40: RTI(); + break; + case 0x41: AddrMode_DirIdxIndX(); + EOR(); + break; + case 0x42: AddrMode_Imm8(); + WDM(); + break; + case 0x43: AddrMode_StkRel(); + EOR(); + break; + case 0x44: AddrMode_BlkMov(); + MVP(); + break; + case 0x45: AddrMode_Dir(); + EOR(); + break; + case 0x46: AddrMode_Dir(); + LSR(); + break; + case 0x47: AddrMode_DirIndLng(); + EOR(); + break; + case 0x48: PHA(); + break; + case 0x49: AddrMode_ImmM(); + EOR(); + break; + case 0x4A: AddrMode_Acc(); + LSR_Acc(); + break; + case 0x4B: PHK(); + break; + case 0x4C: AddrMode_AbsJmp(); + JMP(); + break; + case 0x4D: AddrMode_Abs(); + EOR(); + break; + case 0x4E: AddrMode_Abs(); + LSR(); + break; + case 0x4F: AddrMode_AbsLng(); + EOR(); + break; + case 0x50: AddrMode_Rel(); + BVC(); + break; + case 0x51: AddrMode_DirIndIdxY(false); + EOR(); + break; + case 0x52: AddrMode_DirInd(); + EOR(); + break; + case 0x53: AddrMode_StkRelIndIdxY(); + EOR(); + break; + case 0x54: AddrMode_BlkMov(); + MVN(); + break; + case 0x55: AddrMode_DirIdxX(); + EOR(); + break; + case 0x56: AddrMode_DirIdxX(); + LSR(); + break; + case 0x57: AddrMode_DirIndLngIdxY(); + EOR(); + break; + case 0x58: AddrMode_Imp(); + CLI(); + break; + case 0x59: AddrMode_AbsIdxY(false); + EOR(); + break; + case 0x5A: PHY(); + break; + case 0x5B: AddrMode_Imp(); + TCD(); + break; + case 0x5C: AddrMode_AbsLngJmp(); + JML(); + break; + case 0x5D: AddrMode_AbsIdxX(false); + EOR(); + break; + case 0x5E: AddrMode_AbsIdxX(true); + LSR(); + break; + case 0x5F: AddrMode_AbsLngIdxX(); + EOR(); + break; + case 0x60: RTS(); + break; + case 0x61: AddrMode_DirIdxIndX(); + ADC(); + break; + case 0x62: AddrMode_RelLng(); + PER(); + break; + case 0x63: AddrMode_StkRel(); + ADC(); + break; + case 0x64: AddrMode_Dir(); + STZ(); + break; + case 0x65: AddrMode_Dir(); + ADC(); + break; + case 0x66: AddrMode_Dir(); + ROR(); + break; + case 0x67: AddrMode_DirIndLng(); + ADC(); + break; + case 0x68: PLA(); + break; + case 0x69: AddrMode_ImmM(); + ADC(); + break; + case 0x6A: AddrMode_Acc(); + ROR_Acc(); + break; + case 0x6B: RTL(); + break; + case 0x6C: AddrMode_AbsInd(); + JMP(); + break; + case 0x6D: AddrMode_Abs(); + ADC(); + break; + case 0x6E: AddrMode_Abs(); + ROR(); + break; + case 0x6F: AddrMode_AbsLng(); + ADC(); + break; + case 0x70: AddrMode_Rel(); + BVS(); + break; + case 0x71: AddrMode_DirIndIdxY(false); + ADC(); + break; + case 0x72: AddrMode_DirInd(); + ADC(); + break; + case 0x73: AddrMode_StkRelIndIdxY(); + ADC(); + break; + case 0x74: AddrMode_DirIdxX(); + STZ(); + break; + case 0x75: AddrMode_DirIdxX(); + ADC(); + break; + case 0x76: AddrMode_DirIdxX(); + ROR(); + break; + case 0x77: AddrMode_DirIndLngIdxY(); + ADC(); + break; + case 0x78: AddrMode_Imp(); + SEI(); + break; + case 0x79: AddrMode_AbsIdxY(false); + ADC(); + break; + case 0x7A: PLY(); + break; + case 0x7B: AddrMode_Imp(); + TDC(); + break; + case 0x7C: AddrMode_AbsIdxXInd(); + JMP(); + break; + case 0x7D: AddrMode_AbsIdxX(false); + ADC(); + break; + case 0x7E: AddrMode_AbsIdxX(true); + ROR(); + break; + case 0x7F: AddrMode_AbsLngIdxX(); + ADC(); + break; + case 0x80: AddrMode_Rel(); + BRA(); + break; + case 0x81: AddrMode_DirIdxIndX(); + STA(); + break; + case 0x82: AddrMode_RelLng(); + BRL(); + break; + case 0x83: AddrMode_StkRel(); + STA(); + break; + case 0x84: AddrMode_Dir(); + STY(); + break; + case 0x85: AddrMode_Dir(); + STA(); + break; + case 0x86: AddrMode_Dir(); + STX(); + break; + case 0x87: AddrMode_DirIndLng(); + STA(); + break; + case 0x88: AddrMode_Imp(); + DEY(); + break; + case 0x89: AddrMode_ImmM(); + BIT(); + break; + case 0x8A: AddrMode_Imp(); + TXA(); + break; + case 0x8B: PHB(); + break; + case 0x8C: AddrMode_Abs(); + STY(); + break; + case 0x8D: AddrMode_Abs(); + STA(); + break; + case 0x8E: AddrMode_Abs(); + STX(); + break; + case 0x8F: AddrMode_AbsLng(); + STA(); + break; + case 0x90: AddrMode_Rel(); + BCC(); + break; + case 0x91: AddrMode_DirIndIdxY(true); + STA(); + break; + case 0x92: AddrMode_DirInd(); + STA(); + break; + case 0x93: AddrMode_StkRelIndIdxY(); + STA(); + break; + case 0x94: AddrMode_DirIdxX(); + STY(); + break; + case 0x95: AddrMode_DirIdxX(); + STA(); + break; + case 0x96: AddrMode_DirIdxY(); + STX(); + break; + case 0x97: AddrMode_DirIndLngIdxY(); + STA(); + break; + case 0x98: AddrMode_Imp(); + TYA(); + break; + case 0x99: AddrMode_AbsIdxY(true); + STA(); + break; + case 0x9A: AddrMode_Imp(); + TXS(); + break; + case 0x9B: AddrMode_Imp(); + TXY(); + break; + case 0x9C: AddrMode_Abs(); + STZ(); + break; + case 0x9D: AddrMode_AbsIdxX(true); + STA(); + break; + case 0x9E: AddrMode_AbsIdxX(true); + STZ(); + break; + case 0x9F: AddrMode_AbsLngIdxX(); + STA(); + break; + case 0xA0: AddrMode_ImmX(); + LDY(); + break; + case 0xA1: AddrMode_DirIdxIndX(); + LDA(); + break; + case 0xA2: AddrMode_ImmX(); + LDX(); + break; + case 0xA3: AddrMode_StkRel(); + LDA(); + break; + case 0xA4: AddrMode_Dir(); + LDY(); + break; + case 0xA5: AddrMode_Dir(); + LDA(); + break; + case 0xA6: AddrMode_Dir(); + LDX(); + break; + case 0xA7: AddrMode_DirIndLng(); + LDA(); + break; + case 0xA8: AddrMode_Imp(); + TAY(); + break; + case 0xA9: AddrMode_ImmM(); + LDA(); + break; + case 0xAA: AddrMode_Imp(); + TAX(); + break; + case 0xAB: PLB(); + break; + case 0xAC: AddrMode_Abs(); + LDY(); + break; + case 0xAD: AddrMode_Abs(); + LDA(); + break; + case 0xAE: AddrMode_Abs(); + LDX(); + break; + case 0xAF: AddrMode_AbsLng(); + LDA(); + break; + case 0xB0: AddrMode_Rel(); + BCS(); + break; + case 0xB1: AddrMode_DirIndIdxY(false); + LDA(); + break; + case 0xB2: AddrMode_DirInd(); + LDA(); + break; + case 0xB3: AddrMode_StkRelIndIdxY(); + LDA(); + break; + case 0xB4: AddrMode_DirIdxX(); + LDY(); + break; + case 0xB5: AddrMode_DirIdxX(); + LDA(); + break; + case 0xB6: AddrMode_DirIdxY(); + LDX(); + break; + case 0xB7: AddrMode_DirIndLngIdxY(); + LDA(); + break; + case 0xB8: AddrMode_Imp(); + CLV(); + break; + case 0xB9: AddrMode_AbsIdxY(false); + LDA(); + break; + case 0xBA: AddrMode_Imp(); + TSX(); + break; + case 0xBB: AddrMode_Imp(); + TYX(); + break; + case 0xBC: AddrMode_AbsIdxX(false); + LDY(); + break; + case 0xBD: AddrMode_AbsIdxX(false); + LDA(); + break; + case 0xBE: AddrMode_AbsIdxY(false); + LDX(); + break; + case 0xBF: AddrMode_AbsLngIdxX(); + LDA(); + break; + case 0xC0: AddrMode_ImmX(); + CPY(); + break; + case 0xC1: AddrMode_DirIdxIndX(); + CMP(); + break; + case 0xC2: AddrMode_Imm8(); + REP(); + break; + case 0xC3: AddrMode_StkRel(); + CMP(); + break; + case 0xC4: AddrMode_Dir(); + CPY(); + break; + case 0xC5: AddrMode_Dir(); + CMP(); + break; + case 0xC6: AddrMode_Dir(); + DEC(); + break; + case 0xC7: AddrMode_DirIndLng(); + CMP(); + break; + case 0xC8: AddrMode_Imp(); + INY(); + break; + case 0xC9: AddrMode_ImmM(); + CMP(); + break; + case 0xCA: AddrMode_Imp(); + DEX(); + break; + case 0xCB: AddrMode_Imp(); + WAI(); + break; + case 0xCC: AddrMode_Abs(); + CPY(); + break; + case 0xCD: AddrMode_Abs(); + CMP(); + break; + case 0xCE: AddrMode_Abs(); + DEC(); + break; + case 0xCF: AddrMode_AbsLng(); + CMP(); + break; + case 0xD0: AddrMode_Rel(); + BNE(); + break; + case 0xD1: AddrMode_DirIndIdxY(false); + CMP(); + break; + case 0xD2: AddrMode_DirInd(); + CMP(); + break; + case 0xD3: AddrMode_StkRelIndIdxY(); + CMP(); + break; + case 0xD4: AddrMode_Dir(); + PEI(); + break; + case 0xD5: AddrMode_DirIdxX(); + CMP(); + break; + case 0xD6: AddrMode_DirIdxX(); + DEC(); + break; + case 0xD7: AddrMode_DirIndLngIdxY(); + CMP(); + break; + case 0xD8: AddrMode_Imp(); + CLD(); + break; + case 0xD9: AddrMode_AbsIdxY(false); + CMP(); + break; + case 0xDA: PHX(); + break; + case 0xDB: AddrMode_Imp(); + STP(); + break; + case 0xDC: AddrMode_AbsIndLng(); + JML(); + break; + case 0xDD: AddrMode_AbsIdxX(false); + CMP(); + break; + case 0xDE: AddrMode_AbsIdxX(true); + DEC(); + break; + case 0xDF: AddrMode_AbsLngIdxX(); + CMP(); + break; + case 0xE0: AddrMode_ImmX(); + CPX(); + break; + case 0xE1: AddrMode_DirIdxIndX(); + SBC(); + break; + case 0xE2: AddrMode_Imm8(); + SEP(); + break; + case 0xE3: AddrMode_StkRel(); + SBC(); + break; + case 0xE4: AddrMode_Dir(); + CPX(); + break; + case 0xE5: AddrMode_Dir(); + SBC(); + break; + case 0xE6: AddrMode_Dir(); + INC(); + break; + case 0xE7: AddrMode_DirIndLng(); + SBC(); + break; + case 0xE8: AddrMode_Imp(); + INX(); + break; + case 0xE9: AddrMode_ImmM(); + SBC(); + break; + case 0xEA: AddrMode_Imp(); + NOP(); + break; + case 0xEB: AddrMode_Imp(); + XBA(); + break; + case 0xEC: AddrMode_Abs(); + CPX(); + break; + case 0xED: AddrMode_Abs(); + SBC(); + break; + case 0xEE: AddrMode_Abs(); + INC(); + break; + case 0xEF: AddrMode_AbsLng(); + SBC(); + break; + case 0xF0: AddrMode_Rel(); + BEQ(); + break; + case 0xF1: AddrMode_DirIndIdxY(false); + SBC(); + break; + case 0xF2: AddrMode_DirInd(); + SBC(); + break; + case 0xF3: AddrMode_StkRelIndIdxY(); + SBC(); + break; + case 0xF4: AddrMode_Imm16(); + PEA(); + break; + case 0xF5: AddrMode_DirIdxX(); + SBC(); + break; + case 0xF6: AddrMode_DirIdxX(); + INC(); + break; + case 0xF7: AddrMode_DirIndLngIdxY(); + SBC(); + break; + case 0xF8: AddrMode_Imp(); + SED(); + break; + case 0xF9: AddrMode_AbsIdxY(false); + SBC(); + break; + case 0xFA: PLX(); + break; + case 0xFB: AddrMode_Imp(); + XCE(); + break; + case 0xFC: AddrMode_AbsIdxXInd(); + JSR(); + break; + case 0xFD: AddrMode_AbsIdxX(false); + SBC(); + break; + case 0xFE: AddrMode_AbsIdxX(true); + INC(); + break; + case 0xFF: AddrMode_AbsLngIdxX(); + SBC(); + break; } } @@ -319,7 +817,8 @@ void Cpu::DetectNmiSignalEdge() //"This edge detector polls the status of the NMI line during φ2 of each CPU cycle (i.e., during the //second half of each cycle) and raises an internal signal if the input goes from being high during //one cycle to being low during the next" - if(!_state.PrevNmiFlag && _state.NmiFlag) { + if (!_state.PrevNmiFlag && _state.NmiFlag) + { _state.NeedNmi = true; } _state.PrevNmiFlag = _state.NmiFlag; @@ -327,7 +826,8 @@ void Cpu::DetectNmiSignalEdge() void Cpu::UpdateIrqNmiFlags() { - if(!_state.IrqLock) { + if (!_state.IrqLock) + { //"The internal signal goes high during φ1 of the cycle that follows the one where the edge is detected, //and stays high until the NMI has been handled. " _state.PrevNeedNmi = _state.NeedNmi; @@ -343,9 +843,12 @@ void Cpu::SetIrqSource(IrqSource source) bool Cpu::CheckIrqSource(IrqSource source) { - if(_state.IrqSource & (uint8_t)source) { + if (_state.IrqSource & (uint8_t)source) + { return true; - } else { + } + else + { return false; } } @@ -374,9 +877,12 @@ uint8_t Cpu::GetOpCode() void Cpu::IdleOrRead() { - if(_state.PrevIrqSource) { + if (_state.PrevIrqSource) + { ReadCode(_state.PC); - } else { + } + else + { Idle(); } } @@ -443,18 +949,24 @@ void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type) uint8_t Cpu::GetByteValue() { - if(_immediateMode) { + if (_immediateMode) + { return (uint8_t)_operand; - } else { + } + else + { return ReadData(_operand); } } uint16_t Cpu::GetWordValue() { - if(_immediateMode) { + if (_immediateMode) + { return (uint16_t)_operand; - } else { + } + else + { return ReadDataWord(_operand); } } @@ -486,10 +998,13 @@ uint16_t Cpu::PopWord() uint16_t Cpu::GetDirectAddress(uint16_t offset, bool allowEmulationMode) { - if(allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0) { + if (allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0) + { //TODO: Check if new instruction or not (PEI) return (uint16_t)((_state.D & 0xFF00) | (offset & 0xFF)); - } else { + } + else + { return (uint16_t)(_state.D + offset); } } @@ -511,9 +1026,12 @@ uint32_t Cpu::GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationM void Cpu::SetSP(uint16_t sp) { - if(_state.EmulationMode) { + if (_state.EmulationMode) + { _state.SP = 0x100 | (sp & 0xFF); - } else { + } + else + { _state.SP = sp; } } @@ -521,25 +1039,29 @@ void Cpu::SetSP(uint16_t sp) void Cpu::SetPS(uint8_t ps) { _state.PS = ps; - if(CheckFlag(ProcFlags::IndexMode8)) { + if (CheckFlag(ProcFlags::IndexMode8)) + { //Truncate X/Y when 8-bit indexes are enabled _state.Y &= 0xFF; _state.X &= 0xFF; } } -void Cpu::SetRegister(uint8_t ®, uint8_t value) +void Cpu::SetRegister(uint8_t& reg, uint8_t value) { SetZeroNegativeFlags(value); reg = value; } -void Cpu::SetRegister(uint16_t ®, uint16_t value, bool eightBitMode) +void Cpu::SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode) { - if(eightBitMode) { + if (eightBitMode) + { SetZeroNegativeFlags((uint8_t)value); reg = (reg & 0xFF00) | (uint8_t)value; - } else { + } + else + { SetZeroNegativeFlags(value); reg = value; } @@ -548,9 +1070,12 @@ void Cpu::SetRegister(uint16_t ®, uint16_t value, bool eightBitMode) void Cpu::SetZeroNegativeFlags(uint16_t value) { ClearFlags(ProcFlags::Zero | ProcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(ProcFlags::Zero); - } else if(value & 0x8000) { + } + else if (value & 0x8000) + { SetFlags(ProcFlags::Negative); } } @@ -558,9 +1083,12 @@ void Cpu::SetZeroNegativeFlags(uint16_t value) void Cpu::SetZeroNegativeFlags(uint8_t value) { ClearFlags(ProcFlags::Zero | ProcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(ProcFlags::Zero); - } else if(value & 0x80) { + } + else if (value & 0x80) + { SetFlags(ProcFlags::Negative); } } @@ -580,7 +1108,7 @@ bool Cpu::CheckFlag(uint8_t flag) return (_state.PS & flag) == flag; } -void Cpu::Serialize(Serializer &s) +void Cpu::Serialize(Serializer& s) { s.Stream( _state.A, _state.CycleCount, _state.D, _state.DBR, _state.EmulationMode, _state.IrqSource, _state.K, diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index 494efb4..b00102f 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -26,24 +26,27 @@ void Cpu::Exec() { _immediateMode = false; - switch(_state.StopState) { - case CpuStopState::Running: RunOp(); break; - case CpuStopState::Stopped: - //STP was executed, CPU no longer executes any code - #ifndef DUMMYCPU + switch (_state.StopState) + { + case CpuStopState::Running: RunOp(); + break; + case CpuStopState::Stopped: + //STP was executed, CPU no longer executes any code +#ifndef DUMMYCPU _memoryManager->IncMasterClock4(); - #endif - return; +#endif + return; - case CpuStopState::WaitingForIrq: - //WAI + case CpuStopState::WaitingForIrq: + //WAI + Idle(); + if (_state.IrqSource || _state.NeedNmi) + { Idle(); - if(_state.IrqSource || _state.NeedNmi) { - Idle(); - Idle(); - _state.StopState = CpuStopState::Running; - } - break; + Idle(); + _state.StopState = CpuStopState::Running; + } + break; } #ifndef DUMMYCPU @@ -120,21 +123,33 @@ 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(flag); } diff --git a/Core/Cpu.h b/Core/Cpu.h index 962a93f..8c38c8a 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -29,11 +29,11 @@ private: static constexpr uint32_t LegacyIrqVector = 0xFFFE; static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4; - typedef void(Cpu::*Func)(); - - MemoryManager *_memoryManager = nullptr; - DmaController *_dmaController = nullptr; - Console *_console = nullptr; + typedef void (Cpu::*Func)(); + + MemoryManager* _memoryManager = nullptr; + DmaController* _dmaController = nullptr; + Console* _console = nullptr; bool _immediateMode = false; @@ -47,9 +47,9 @@ private: uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true); uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true); - + uint8_t GetOpCode(); - + uint16_t GetResetVector(); void UpdateIrqNmiFlags(); @@ -59,7 +59,7 @@ private: void IdleOrRead(); void IdleEndJump(); void IdleTakeBranch(); - + uint8_t ReadOperandByte(); uint16_t ReadOperandWord(); uint32_t ReadOperandLong(); @@ -71,9 +71,9 @@ private: void SetSP(uint16_t sp); void SetPS(uint8_t ps); - void SetRegister(uint8_t ®, uint8_t value); - void SetRegister(uint16_t ®, 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); @@ -109,7 +109,7 @@ private: void Sub8(uint8_t value); void Sub16(uint16_t value); void SBC(); - + //Branch instructions void BCC(); void BCS(); @@ -122,7 +122,7 @@ private: void BVC(); void BVS(); void BranchRelative(bool branch); - + //Set/clear flag instructions void CLC(); void CLD(); @@ -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,10 +174,14 @@ private: void EOR(); void ORA(); - template T ShiftLeft(T value); - template T RollLeft(T value); - template T ShiftRight(T value); - template T RollRight(T value); + template + T ShiftLeft(T value); + template + T RollLeft(T value); + template + T ShiftRight(T value); + template + T RollRight(T value); //Shift operations void ASL_Acc(); @@ -213,10 +217,10 @@ private: void PLY(); void PushRegister(uint16_t reg, bool eightBitMode); - void PullRegister(uint16_t ®, bool eightBitMode); + void PullRegister(uint16_t& reg, bool eightBitMode); //Store/load instructions - void LoadRegister(uint16_t ®, bool eightBitMode); + void LoadRegister(uint16_t& reg, bool eightBitMode); void StoreRegister(uint16_t val, bool eightBitMode); void LDA(); @@ -227,9 +231,10 @@ private: void STX(); void STY(); void STZ(); - + //Test bits - template void TestBits(T value, bool alterZeroFlagOnly); + template + void TestBits(T value, bool alterZeroFlagOnly); void BIT(); void TRB(); @@ -282,7 +287,7 @@ private: void AddrMode_BlkMov(); uint8_t ReadDirectOperandByte(); - + //Direct: d void AddrMode_Dir(); //Direct Indexed: d,x @@ -291,7 +296,7 @@ private: void AddrMode_DirIdxY(); //Direct Indirect: (d) void AddrMode_DirInd(); - + //Direct Indexed Indirect: (d,x) void AddrMode_DirIdxIndX(); //Direct Indirect Indexed: (d),y @@ -313,12 +318,12 @@ private: void AddrMode_StkRel(); void AddrMode_StkRelIndIdxY(); - + void RunOp(); public: #ifndef DUMMYCPU - Cpu(Console *console); + Cpu(Console* console); #else DummyCpu(Console* console, CpuType type); #endif @@ -334,7 +339,7 @@ public: bool GetCpuProcFlag(ProcFlags::ProcFlags flag); uint64_t GetCycleCount(); - template + template void IncreaseCycleCount(); void SetNmiFlag(bool nmiFlag); @@ -345,7 +350,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); @@ -377,10 +382,10 @@ public: void SetReg(CpuRegister reg, uint16_t value); -template +template void Cpu::IncreaseCycleCount() { _state.CycleCount += count; } -#endif \ No newline at end of file +#endif diff --git a/Core/CpuBwRamHandler.h b/Core/CpuBwRamHandler.h index 9e12f8c..72d1f04 100644 --- a/Core/CpuBwRamHandler.h +++ b/Core/CpuBwRamHandler.h @@ -10,7 +10,7 @@ class CpuBwRamHandler : public IMemoryHandler { private: - IMemoryHandler * _handler; + IMemoryHandler* _handler; Sa1State* _state; Sa1* _sa1; @@ -24,9 +24,12 @@ public: uint8_t Read(uint32_t addr) override { - if(_state->CharConvDmaActive) { + if (_state->CharConvDmaActive) + { return _sa1->ReadCharConvertType1(addr); - } else { + } + else + { return _handler->Read(addr); } } @@ -36,7 +39,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); } @@ -50,4 +53,4 @@ public: { return _handler->GetAbsoluteAddress(address); } -}; \ No newline at end of file +}; diff --git a/Core/CpuDebugger.cpp b/Core/CpuDebugger.cpp index 4245259..ef0a3fd 100644 --- a/Core/CpuDebugger.cpp +++ b/Core/CpuDebugger.cpp @@ -36,14 +36,16 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType) _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _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; } @@ -59,26 +61,34 @@ 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); @@ -86,19 +96,25 @@ 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; } @@ -106,47 +122,72 @@ 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; } @@ -154,22 +195,27 @@ 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); } @@ -186,25 +232,39 @@ 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; - case StepType::StepOver: - 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 { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - 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) + { + //JSR, JSL, BRK, COP, MVP, MVN + 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)); @@ -215,20 +275,24 @@ 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); } @@ -236,18 +300,24 @@ 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(); } } @@ -275,4 +345,4 @@ shared_ptr CpuDebugger::GetCallstackManager() BreakpointManager* CpuDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/CpuDebugger.h b/Core/CpuDebugger.h index 9ae83ab..f869051 100644 --- a/Core/CpuDebugger.h +++ b/Core/CpuDebugger.h @@ -62,4 +62,4 @@ public: shared_ptr GetAssembler(); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/CpuDisUtils.cpp b/Core/CpuDisUtils.cpp index b776a29..1ab1c0d 100644 --- a/Core/CpuDisUtils.cpp +++ b/Core/CpuDisUtils.cpp @@ -10,7 +10,8 @@ #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)); @@ -23,80 +24,127 @@ 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; - 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; + 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::Imm8: case AddrMode::Imm16: case AddrMode::ImmX: case AddrMode::ImmM: - str.WriteAll('#', operand); - break; + 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::Imp: 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::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::Stk: 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"); + default: throw std::runtime_error("invalid address mode"); } 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); } } @@ -104,9 +152,10 @@ 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(); @@ -119,41 +168,42 @@ int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console bool CpuDisUtils::HasEffectiveAddress(AddrMode addrMode) { - switch(addrMode) { - case AddrMode::Acc: - case AddrMode::Imp: - case AddrMode::Stk: - case AddrMode::Sig8: - case AddrMode::Imm8: - case AddrMode::Rel: - case AddrMode::RelLng: - case AddrMode::Imm16: - case AddrMode::BlkMov: - case AddrMode::AbsLngJmp: - case AddrMode::AbsLng: - case AddrMode::ImmX: - case AddrMode::ImmM: - case AddrMode::AbsJmp: - return false; + switch (addrMode) + { + case AddrMode::Acc: + case AddrMode::Imp: + case AddrMode::Stk: + case AddrMode::Sig8: + case AddrMode::Imm8: + case AddrMode::Rel: + case AddrMode::RelLng: + case AddrMode::Imm16: + case AddrMode::BlkMov: + case AddrMode::AbsLngJmp: + case AddrMode::AbsLng: + case AddrMode::ImmX: + case AddrMode::ImmM: + case AddrMode::AbsJmp: + return false; - case AddrMode::DirIdxIndX: - case AddrMode::DirIdxX: - case AddrMode::DirIdxY: - case AddrMode::DirIndIdxY: - case AddrMode::DirIndLngIdxY: - case AddrMode::DirIndLng: - case AddrMode::DirInd: - case AddrMode::Dir: - case AddrMode::StkRel: - case AddrMode::StkRelIndIdxY: - case AddrMode::Abs: - case AddrMode::AbsIdxXInd: - case AddrMode::AbsIdxX: - case AddrMode::AbsIdxY: - case AddrMode::AbsLngIdxX: - case AddrMode::AbsInd: - case AddrMode::AbsIndLng: - return true; + case AddrMode::DirIdxIndX: + case AddrMode::DirIdxX: + case AddrMode::DirIdxY: + case AddrMode::DirIndIdxY: + case AddrMode::DirIndLngIdxY: + case AddrMode::DirIndLng: + case AddrMode::DirInd: + case AddrMode::Dir: + case AddrMode::StkRel: + case AddrMode::StkRelIndIdxY: + case AddrMode::Abs: + case AddrMode::AbsIdxXInd: + case AddrMode::AbsIdxX: + case AddrMode::AbsIdxY: + case AddrMode::AbsLngIdxX: + case AddrMode::AbsInd: + case AddrMode::AbsIndLng: + return true; } throw std::runtime_error("Invalid mode"); @@ -161,9 +211,12 @@ 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; } @@ -199,26 +252,42 @@ string CpuDisUtils::OpName[256] = { "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", // C "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", // D "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", // E - "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F + "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F }; 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 -}; \ No newline at end of file + 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 +}; diff --git a/Core/CpuDisUtils.h b/Core/CpuDisUtils.h index a6f2a45..b6beb05 100644 --- a/Core/CpuDisUtils.h +++ b/Core/CpuDisUtils.h @@ -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,9 +22,10 @@ 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 @@ -35,15 +36,20 @@ 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, @@ -60,4 +66,4 @@ enum class AddrMode : uint8_t Stk, StkRel, StkRelIndIdxY -}; \ No newline at end of file +}; diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index 61c805b..57549e4 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -15,7 +15,7 @@ struct CpuState uint16_t A; uint16_t X; uint16_t Y; - + /* 16-bit stack pointer */ uint16_t SP; @@ -88,4 +88,3 @@ enum class IrqSource Ppu = 1, Coprocessor = 2 }; - diff --git a/Core/Cx4.Instructions.cpp b/Core/Cx4.Instructions.cpp index d266699..9b08837 100644 --- a/Core/Cx4.Instructions.cpp +++ b/Core/Cx4.Instructions.cpp @@ -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,86 +14,151 @@ 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); @@ -101,119 +166,177 @@ void Cx4::Exec(uint16_t opCode) uint32_t Cx4::GetSourceValue(uint8_t src) { - switch(src & 0x7F) { - case 0x00: return _state.A; - case 0x01: return (_state.Mult >> 24) & 0xFFFFFF; - case 0x02: return _state.Mult & 0xFFFFFF; - case 0x03: return _state.MemoryDataReg; - case 0x08: return _state.RomBuffer; - case 0x0C: return (_state.RamBuffer[2] << 16) | (_state.RamBuffer[1] << 8) | _state.RamBuffer[0]; - case 0x13: return _state.MemoryAddressReg; - case 0x1C: return _state.DataPointerReg; - case 0x20: return _state.PC; - case 0x28: return _state.P; + switch (src & 0x7F) + { + case 0x00: return _state.A; + case 0x01: return (_state.Mult >> 24) & 0xFFFFFF; + case 0x02: return _state.Mult & 0xFFFFFF; + case 0x03: return _state.MemoryDataReg; + case 0x08: return _state.RomBuffer; + case 0x0C: return (_state.RamBuffer[2] << 16) | (_state.RamBuffer[1] << 8) | _state.RamBuffer[0]; + case 0x13: return _state.MemoryAddressReg; + case 0x1C: return _state.DataPointerReg; + case 0x20: return _state.PC; + case 0x28: return _state.P; - case 0x2E: - _state.Bus.Enabled = true; - _state.Bus.Reading = true; - _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - return 0; + case 0x2E: + _state.Bus.Enabled = true; + _state.Bus.Reading = true; + _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + return 0; - case 0x2F: - _state.Bus.Enabled = true; - _state.Bus.Reading = true; - _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - return 0; + case 0x2F: + _state.Bus.Enabled = true; + _state.Bus.Reading = true; + _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + return 0; - case 0x50: return 0x000000; - case 0x51: return 0xFFFFFF; - case 0x52: return 0x00FF00; - case 0x53: return 0xFF0000; - case 0x54: return 0x00FFFF; - case 0x55: return 0xFFFF00; - case 0x56: return 0x800000; - case 0x57: return 0x7FFFFF; - case 0x58: return 0x008000; - case 0x59: return 0x007FFF; - case 0x5A: return 0xFF7FFF; - case 0x5B: return 0xFFFF7F; - case 0x5C: return 0x010000; - case 0x5D: return 0xFEFFFF; - case 0x5E: return 0x000100; - case 0x5F: return 0x00FEFF; + case 0x50: return 0x000000; + case 0x51: return 0xFFFFFF; + case 0x52: return 0x00FF00; + case 0x53: return 0xFF0000; + case 0x54: return 0x00FFFF; + case 0x55: return 0xFFFF00; + case 0x56: return 0x800000; + case 0x57: return 0x7FFFFF; + case 0x58: return 0x008000; + case 0x59: return 0x007FFF; + case 0x5A: return 0xFF7FFF; + case 0x5B: return 0xFFFF7F; + case 0x5C: return 0x010000; + case 0x5D: return 0xFEFFFF; + 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; } -void Cx4::WriteRegister(uint8_t reg, uint32_t value) +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; - case 0x0C: - _state.RamBuffer[0] = value; - _state.RamBuffer[1] = value >> 8; - _state.RamBuffer[2] = value >> 16; - 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 0x2E: - _state.Bus.Enabled = true; - _state.Bus.Writing = true; - _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - 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 0x2F: - _state.Bus.Enabled = true; - _state.Bus.Writing = true; - _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - break; + case 0x2E: + _state.Bus.Enabled = true; + _state.Bus.Writing = true; + _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; + _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 0x2F: + _state.Bus.Enabled = true; + _state.Bus.Writing = true; + _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; + _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; } } @@ -228,7 +351,8 @@ void Cx4::NOP() void Cx4::WAIT() { - if(_state.Bus.Enabled) { + if (_state.Bus.Enabled) + { Step(_state.Bus.DelayCycles); } } @@ -236,17 +360,24 @@ void Cx4::WAIT() void Cx4::Skip(uint8_t flagToCheck, uint8_t skipIfSet) { bool skip; - 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; + 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; } - if(skip) { + if (skip) + { _state.PC++; - if(_state.PC == 0) { + if (_state.PC == 0) + { SwitchCachePage(); } Step(1); @@ -255,8 +386,10 @@ 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; @@ -266,9 +399,11 @@ 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; @@ -348,11 +483,14 @@ 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; @@ -361,21 +499,31 @@ 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; } } @@ -471,7 +619,8 @@ 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(); @@ -480,7 +629,8 @@ 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(); @@ -489,7 +639,8 @@ 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(); @@ -498,7 +649,8 @@ 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(); @@ -507,7 +659,8 @@ 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(); @@ -516,7 +669,8 @@ 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(); @@ -525,7 +679,8 @@ 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(); @@ -534,7 +689,8 @@ 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(); @@ -552,12 +708,14 @@ 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; } @@ -566,12 +724,14 @@ 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]; @@ -579,12 +739,14 @@ 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; } @@ -593,12 +755,14 @@ 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]; @@ -606,10 +770,13 @@ 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; - default: break; //nop + 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 } } @@ -622,17 +789,21 @@ 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; - default: break; //nop + switch (src) + { + case 0: WriteRegister(dst, _state.A); + break; + case 1: WriteRegister(dst, _state.MemoryDataReg); + break; + default: break; //nop } } void Cx4::Stop() { _state.Stopped = true; - if(!_state.IrqDisabled) { + if (!_state.IrqDisabled) + { _state.IrqFlag = true; _cpu->SetIrqSource(IrqSource::Coprocessor); } @@ -645,68 +816,132 @@ 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 }; diff --git a/Core/Cx4.cpp b/Core/Cx4.cpp index bbbb369..0d08ac1 100644 --- a/Core/Cx4.cpp +++ b/Core/Cx4.cpp @@ -19,11 +19,11 @@ Cx4::Cx4(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _memoryType = SnesMemoryType::Register; _memoryManager = console->GetMemoryManager().get(); _cpu = console->GetCpu().get(); - + 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,36 +62,56 @@ 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(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(); @@ -104,19 +124,25 @@ 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; } @@ -128,21 +154,24 @@ 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; - } + } _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(); } } @@ -151,8 +180,10 @@ 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; @@ -161,28 +192,32 @@ 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; } - + _state.Cache.Enabled = true; } //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))); @@ -192,12 +227,14 @@ 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; @@ -210,13 +247,16 @@ 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; @@ -231,12 +271,14 @@ 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; } @@ -245,9 +287,12 @@ 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; } @@ -257,7 +302,8 @@ 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(addr, value, MemoryOperationType::Read); return value; @@ -268,7 +314,8 @@ 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(addr, value, MemoryOperationType::Write); handler->Write(addr, value); } @@ -277,42 +324,52 @@ 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 ® = _state.Regs[addr / 3]; - switch(addr % 3) { - case 0: return reg; - case 1: return reg >> 8; - case 2: return reg >> 16; + 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) { - case 0x7F40: return _state.Dma.Source; - case 0x7F41: return _state.Dma.Source >> 8; - case 0x7F42: return _state.Dma.Source >> 16; - case 0x7F43: return (uint8_t)_state.Dma.Length; - case 0x7F44: return _state.Dma.Length >> 8; - case 0x7F45: return _state.Dma.Dest; - case 0x7F46: return _state.Dma.Dest >> 8; - case 0x7F47: return _state.Dma.Dest >> 16; - case 0x7F48: return _state.Cache.Page; - case 0x7F49: return _state.Cache.Base; - case 0x7F4A: return _state.Cache.Base >> 8; - case 0x7F4B: return _state.Cache.Base >> 16; - case 0x7F4C: return (uint8_t)_state.Cache.Lock[0] | ((uint8_t)_state.Cache.Lock[1] << 1); - case 0x7F4D: return (uint8_t)_state.Cache.ProgramBank; - case 0x7F4E: return _state.Cache.ProgramBank >> 8; - case 0x7F4F: return _state.Cache.ProgramCounter; - case 0x7F50: return _state.RamAccessDelay | (_state.RomAccessDelay << 4); - case 0x7F51: return _state.IrqDisabled; - case 0x7F52: return _state.SingleRom; + switch (addr) + { + case 0x7F40: return _state.Dma.Source; + case 0x7F41: return _state.Dma.Source >> 8; + case 0x7F42: return _state.Dma.Source >> 16; + case 0x7F43: return (uint8_t)_state.Dma.Length; + case 0x7F44: return _state.Dma.Length >> 8; + case 0x7F45: return _state.Dma.Dest; + case 0x7F46: return _state.Dma.Dest >> 8; + case 0x7F47: return _state.Dma.Dest >> 16; + case 0x7F48: return _state.Cache.Page; + case 0x7F49: return _state.Cache.Base; + case 0x7F4A: return _state.Cache.Base >> 8; + case 0x7F4B: return _state.Cache.Base >> 16; + case 0x7F4C: return (uint8_t)_state.Cache.Lock[0] | ((uint8_t)_state.Cache.Lock[1] << 1); + case 0x7F4D: return (uint8_t)_state.Cache.ProgramBank; + case 0x7F4E: return _state.Cache.ProgramBank >> 8; + case 0x7F4F: return _state.Cache.ProgramCounter; + case 0x7F50: return _state.RamAccessDelay | (_state.RomAccessDelay << 4); + case 0x7F51: return _state.IrqDisabled; + case 0x7F52: return _state.SingleRom; } return 0; @@ -322,94 +379,125 @@ 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 ® = _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; - case 0x7F47: - _state.Dma.Dest = (_state.Dma.Dest & 0x00FFFF) | (value << 16); - if(_state.Stopped) { - _state.Dma.Enabled = true; - } - 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) + { + _state.Dma.Enabled = true; + } + break; - case 0x7F48: - _state.Cache.Page = value & 0x01; - if(_state.Stopped) { - _state.Cache.Enabled = true; - } - break; + case 0x7F48: + _state.Cache.Page = value & 0x01; + 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 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) { - _state.Stopped = false; - _state.PB = _state.Cache.ProgramBank; - _state.PC = _state.Cache.ProgramCounter; - } - break; + case 0x7F4F: + _state.Cache.ProgramCounter = value; + if (_state.Stopped) + { + _state.Stopped = false; + _state.PB = _state.Cache.ProgramBank; + _state.PC = _state.Cache.ProgramCounter; + } + break; - case 0x7F50: - _state.RamAccessDelay = value & 0x07; - _state.RomAccessDelay = (value >> 4) & 0x07; - break; + case 0x7F50: + _state.RamAccessDelay = value & 0x07; + _state.RomAccessDelay = (value >> 4) & 0x07; + break; - case 0x7F51: - _state.IrqDisabled = value & 0x01; - if(_state.IrqDisabled) { - _state.IrqFlag = true; - _cpu->ClearIrqSource(IrqSource::Coprocessor); - } - break; + case 0x7F51: + _state.IrqDisabled = value & 0x01; + 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 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 - _state.IrqFlag = false; - break; + case 0x7F5E: + //Clear IRQ flag in CX4, but keeps IRQ signal high + _state.IrqFlag = false; + break; } } } @@ -424,19 +512,23 @@ 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 ); - + s.StreamArray(_state.Stack, 8); s.StreamArray(_state.Regs, 16); s.StreamArray(_state.Vectors, 0x20); @@ -457,7 +549,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() @@ -484,31 +576,48 @@ 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(reg) - static_cast(Cx4Register::Cx4Reg0)) & 0x0F] = value & 0xFFFFFF; // 24-bit break; case Cx4Register::Cx4RegPB: - { - _state.PB = value & 0xFFFF; - } break; + { + _state.PB = value & 0xFFFF; + } + break; case Cx4Register::Cx4RegPC: - { - _state.PC = value & 0xFF; - } break; + { + _state.PC = value & 0xFF; + } + break; case Cx4Register::Cx4RegA: - { - _state.A = value & 0xFFFFFF; // 24-bit - } break; + { + _state.A = value & 0xFFFFFF; // 24-bit + } + break; case Cx4Register::Cx4RegP: - { - _state.P = value & 0xFFFF; - } break; + { + _state.P = value & 0xFFFF; + } + break; case Cx4Register::Cx4RegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; } -} \ No newline at end of file +} diff --git a/Core/Cx4.h b/Core/Cx4.h index d18e50c..889acf9 100644 --- a/Core/Cx4.h +++ b/Core/Cx4.h @@ -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; @@ -131,4 +131,4 @@ public: Cx4State GetState(); void SetReg(Cx4Register reg, uint32_t value); -}; \ No newline at end of file +}; diff --git a/Core/Cx4Debugger.cpp b/Core/Cx4Debugger.cpp index 4c0de7d..ed415e4 100644 --- a/Core/Cx4Debugger.cpp +++ b/Core/Cx4Debugger.cpp @@ -42,19 +42,23 @@ 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); @@ -65,14 +69,18 @@ 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()); @@ -84,7 +92,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()); } @@ -98,17 +106,19 @@ 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: - step.StepCount = 1; - break; + case StepType::StepOut: + case StepType::StepOver: + step.StepCount = 1; + break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -117,4 +127,4 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type) BreakpointManager* Cx4Debugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/Cx4Debugger.h b/Core/Cx4Debugger.h index 653adfa..518943e 100644 --- a/Core/Cx4Debugger.h +++ b/Core/Cx4Debugger.h @@ -40,4 +40,4 @@ public: void Run(); void Step(int32_t stepCount, StepType type); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/Cx4DisUtils.cpp b/Core/Cx4DisUtils.cpp index b69f46b..e299d5e 100644 --- a/Core/Cx4DisUtils.cpp +++ b/Core/Cx4DisUtils.cpp @@ -5,7 +5,8 @@ #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)); @@ -13,197 +14,417 @@ 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; - 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; + 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 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; - } - str.Write((param2 & 0x01) ? 'S' : 'C'); + 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 0x24: + str.Write("SKIP"); + switch (param1) + { + case 0: str.Write('V'); 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 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 0x58: - if(param1 == 1) { - str.Write("SXB"); - } else if(param1 == 2) { - str.Write("SXW"); - } else { - str.Write("???"); - } + case 1: str.Write('C'); 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 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 0x7C: - if(param1 <= 1) { - str.WriteAll("LD P", param1 ? "H" : "L", ",#$", HexUtilities::ToHex(param2)); - } else { - str.Write("???"); - } + case 2: str.Write('Z'); 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 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 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 0xE0: - if(param1 <= 1) { - str.Write("ST "); writeSrc(); str.WriteAll(",", param1 ? "MDR" : "A"); - } else { - str.Write("???"); - } + case 3: str.Write('N'); 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; + } + str.Write((param2 & 0x01) ? 'S' : 'C'); + 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 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 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 0x58: + if (param1 == 1) + { + str.Write("SXB"); + } + else if (param1 == 2) + { + str.Write("SXW"); + } + else + { + 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 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 0x7C: + if (param1 <= 1) + { + str.WriteAll("LD P", param1 ? "H" : "L", ",#$", HexUtilities::ToHex(param2)); + } + 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 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 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 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 + { + 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 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(); diff --git a/Core/Cx4DisUtils.h b/Core/Cx4DisUtils.h index c04b2b7..504d6df 100644 --- a/Core/Cx4DisUtils.h +++ b/Core/Cx4DisUtils.h @@ -8,5 +8,6 @@ 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); }; diff --git a/Core/Cx4Types.h b/Core/Cx4Types.h index 314888c..6057b73 100644 --- a/Core/Cx4Types.h +++ b/Core/Cx4Types.h @@ -48,7 +48,7 @@ struct Cx4State uint8_t PC; //Accumulator - uint32_t A; + uint32_t A; //Page register uint16_t P; @@ -76,7 +76,7 @@ struct Cx4State bool Stopped; bool Locked; bool IrqDisabled; - + bool SingleRom; uint8_t RomAccessDelay; @@ -87,4 +87,4 @@ struct Cx4State Cx4Cache Cache; Cx4Suspend Suspend; uint8_t Vectors[0x20]; -}; \ No newline at end of file +}; diff --git a/Core/DebugBreakHelper.h b/Core/DebugBreakHelper.h index c7f012c..94bcf26 100644 --- a/Core/DebugBreakHelper.h +++ b/Core/DebugBreakHelper.h @@ -6,7 +6,7 @@ class DebugBreakHelper { private: - Debugger * _debugger; + Debugger* _debugger; bool _needResume = false; bool _isEmulationThread = false; @@ -17,11 +17,15 @@ 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; } } @@ -29,8 +33,9 @@ public: ~DebugBreakHelper() { - if(!_isEmulationThread) { + if (!_isEmulationThread) + { _debugger->BreakRequest(true); } } -}; \ No newline at end of file +}; diff --git a/Core/DebugHud.cpp b/Core/DebugHud.cpp index 14d1d60..9831277 100644 --- a/Core/DebugHud.cpp +++ b/Core/DebugHud.cpp @@ -27,16 +27,19 @@ void DebugHud::ClearScreen() void DebugHud::Draw(uint32_t* argbBuffer, OverscanDimensions overscan, uint32_t lineWidth, uint32_t frameNumber) { auto lock = _commandLock.AcquireSafe(); - for(unique_ptr &command : _commands) { + for (unique_ptr& command : _commands) + { command->Draw(argbBuffer, overscan, lineWidth, frameNumber); } - _commands.erase(std::remove_if(_commands.begin(), _commands.end(), [](const unique_ptr& c) { return c->Expired(); }), _commands.end()); + _commands.erase(std::remove_if(_commands.begin(), _commands.end(), + [](const unique_ptr& 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(new DrawPixelCommand(x, y, color, frameCount, startFrame))); } } @@ -44,23 +47,29 @@ 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(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr(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(new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr( + 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(new DrawScreenBufferCommand(screenBuffer, startFrame))); } } @@ -68,7 +77,9 @@ 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(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame))); } } diff --git a/Core/DebugStats.cpp b/Core/DebugStats.cpp index 39b5dfe..f3e4204 100644 --- a/Core/DebugStats.cpp +++ b/Core/DebugStats.cpp @@ -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,21 +23,29 @@ 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]; } @@ -49,10 +57,13 @@ 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; } diff --git a/Core/DebugStats.h b/Core/DebugStats.h index dbf0706..13e5a75 100644 --- a/Core/DebugStats.h +++ b/Core/DebugStats.h @@ -12,5 +12,5 @@ private: double _lastFrameMax = 0; public: - void DisplayStats(Console *console, double lastFrameTime); -}; \ No newline at end of file + void DisplayStats(Console* console, double lastFrameTime); +}; diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index 68c2c80..888530b 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -241,7 +241,7 @@ enum class BreakSource BreakOnWdm = 5, BreakOnStp = 6, BreakOnUninitMemoryRead = 7, - + GbInvalidOamAccess = 8, GbInvalidVramAccess = 9, GbDisableLcdOutsideVblank = 10, diff --git a/Core/DebugUtilities.h b/Core/DebugUtilities.h index 0220e71..215dd45 100644 --- a/Core/DebugUtilities.h +++ b/Core/DebugUtilities.h @@ -7,14 +7,15 @@ class DebugUtilities public: static SnesMemoryType GetCpuMemoryType(CpuType type) { - switch(type) { - case CpuType::Cpu: return SnesMemoryType::CpuMemory; - case CpuType::Spc: return SnesMemoryType::SpcMemory; - case CpuType::NecDsp: return SnesMemoryType::NecDspMemory; - case CpuType::Sa1: return SnesMemoryType::Sa1Memory; - case CpuType::Gsu: return SnesMemoryType::GsuMemory; - case CpuType::Cx4: return SnesMemoryType::Cx4Memory; - case CpuType::Gameboy: return SnesMemoryType::GameboyMemory; + switch (type) + { + case CpuType::Cpu: return SnesMemoryType::CpuMemory; + case CpuType::Spc: return SnesMemoryType::SpcMemory; + case CpuType::NecDsp: return SnesMemoryType::NecDspMemory; + case CpuType::Sa1: return SnesMemoryType::Sa1Memory; + case CpuType::Gsu: return SnesMemoryType::GsuMemory; + case CpuType::Cx4: return SnesMemoryType::Cx4Memory; + case CpuType::Gameboy: return SnesMemoryType::GameboyMemory; } throw std::runtime_error("Invalid CPU type"); @@ -22,41 +23,42 @@ public: static CpuType ToCpuType(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::SpcMemory: - case SnesMemoryType::SpcRam: - case SnesMemoryType::SpcRom: - return CpuType::Spc; + switch (type) + { + case SnesMemoryType::SpcMemory: + case SnesMemoryType::SpcRam: + case SnesMemoryType::SpcRom: + return CpuType::Spc; - case SnesMemoryType::GsuMemory: - case SnesMemoryType::GsuWorkRam: - return CpuType::Gsu; + case SnesMemoryType::GsuMemory: + case SnesMemoryType::GsuWorkRam: + return CpuType::Gsu; - case SnesMemoryType::Sa1InternalRam: - case SnesMemoryType::Sa1Memory: - return CpuType::Sa1; + case SnesMemoryType::Sa1InternalRam: + case SnesMemoryType::Sa1Memory: + return CpuType::Sa1; - case SnesMemoryType::DspDataRam: - case SnesMemoryType::DspDataRom: - case SnesMemoryType::DspProgramRom: - return CpuType::NecDsp; + case SnesMemoryType::DspDataRam: + case SnesMemoryType::DspDataRom: + case SnesMemoryType::DspProgramRom: + return CpuType::NecDsp; - case SnesMemoryType::Cx4DataRam: - case SnesMemoryType::Cx4Memory: - return CpuType::Cx4; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbSpriteRam: - case SnesMemoryType::GameboyMemory: - return CpuType::Gameboy; + case SnesMemoryType::Cx4DataRam: + case SnesMemoryType::Cx4Memory: + return CpuType::Cx4; - default: - return CpuType::Cpu; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbSpriteRam: + case SnesMemoryType::GameboyMemory: + return CpuType::Gameboy; + + default: + return CpuType::Cpu; } throw std::runtime_error("Invalid CPU type"); @@ -69,30 +71,32 @@ public: static bool IsPpuMemory(SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::VideoRam: - case SnesMemoryType::SpriteRam: - case SnesMemoryType::CGRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbSpriteRam: - return true; + switch (memType) + { + case SnesMemoryType::VideoRam: + case SnesMemoryType::SpriteRam: + case SnesMemoryType::CGRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbSpriteRam: + return true; - default: - return false; + default: + return false; } } static bool IsRomMemory(SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::PrgRom: - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram - return true; + switch (memType) + { + case SnesMemoryType::PrgRom: + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram + return true; - default: - return false; + default: + return false; } } @@ -100,4 +104,4 @@ public: { return CpuType::Gameboy; } -}; \ No newline at end of file +}; diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 0d2cf61..db32d2b 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -80,18 +80,26 @@ Debugger::Debugger(shared_ptr console) _ppuTools.reset(new PpuTools(_console.get(), _ppu.get())); _scriptManager.reset(new ScriptManager(this)); - if(_gameboy) { + if (_gameboy) + { _gbDebugger.reset(new GbDebugger(this)); } _cpuDebugger.reset(new CpuDebugger(this, CpuType::Cpu)); _spcDebugger.reset(new SpcDebugger(this)); - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { _sa1Debugger.reset(new CpuDebugger(this, CpuType::Sa1)); - } else if(_cart->GetGsu()) { + } + else if (_cart->GetGsu()) + { _gsuDebugger.reset(new GsuDebugger(this)); - } else if(_cart->GetDsp()) { + } + else if (_cart->GetDsp()) + { _necDspDebugger.reset(new NecDspDebugger(this)); - } else if(_cart->GetCx4()) { + } + else if (_cart->GetCx4()) + { _cx4Debugger.reset(new Cx4Debugger(this)); } @@ -100,12 +108,16 @@ Debugger::Debugger(shared_ptr console) _suspendRequestCount = 0; CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; - string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); - GetCodeDataLogger(cpuType)->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), _cart->GetCrc32()); + string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), + FolderUtilities::GetFilename( + _cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); + GetCodeDataLogger(cpuType)->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), + _cart->GetCrc32()); RefreshCodeCache(); - if(_console->IsPaused()) { + if (_console->IsPaused()) + { Step(CpuType::Cpu, 1, StepType::Step); } _executionStopped = false; @@ -119,10 +131,13 @@ Debugger::~Debugger() void Debugger::Release() { CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; - string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); + string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), + FolderUtilities::GetFilename( + _cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); GetCodeDataLogger(cpuType)->SaveCdlFile(cdlFile, _cart->GetCrc32()); - while(_executionStopped) { + while (_executionStopped) + { Run(); } } @@ -132,71 +147,92 @@ void Debugger::Reset() _memoryAccessCounter->ResetCounts(); _cpuDebugger->Reset(); _spcDebugger->Reset(); - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->Reset(); } } -template +template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Spc: _spcDebugger->ProcessRead(addr, value, opType); break; - case CpuType::NecDsp: _necDspDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); break; - case CpuType::Gsu: _gsuDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Cx4: _cx4Debugger->ProcessRead(addr, value, opType); break; - case CpuType::Gameboy: _gbDebugger->ProcessRead(addr, value, opType); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Spc: _spcDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::NecDsp: _necDspDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); + break; + case CpuType::Gsu: _gsuDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Cx4: _cx4Debugger->ProcessRead(addr, value, opType); + break; + case CpuType::Gameboy: _gbDebugger->ProcessRead(addr, value, opType); + break; } - - if(_scriptManager->HasScript()) { + + if (_scriptManager->HasScript()) + { _scriptManager->ProcessMemoryOperation(addr, value, opType, type); } } -template +template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Spc: _spcDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::NecDsp: _necDspDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); break; - case CpuType::Gsu: _gsuDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Cx4: _cx4Debugger->ProcessWrite(addr, value, opType); break; - case CpuType::Gameboy: _gbDebugger->ProcessWrite(addr, value, opType); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Spc: _spcDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::NecDsp: _necDspDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Gsu: _gsuDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Cx4: _cx4Debugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Gameboy: _gbDebugger->ProcessWrite(addr, value, opType); + break; } - - if(_scriptManager->HasScript()) { + + if (_scriptManager->HasScript()) + { _scriptManager->ProcessMemoryOperation(addr, value, opType, type); } } void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value) { - AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; + AddressInfo addressInfo{(int32_t)addr, SnesMemoryType::WorkRam}; _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); - - MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Read }; + + MemoryOperationInfo operation{0x7E0000 | addr, value, MemoryOperationType::Read}; ProcessBreakConditions(false, _cpuDebugger->GetBreakpointManager(), operation, addressInfo); } void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value) { - AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; + AddressInfo addressInfo{(int32_t)addr, SnesMemoryType::WorkRam}; _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); - - MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Write }; + + MemoryOperationInfo operation{0x7E0000 | addr, value, MemoryOperationType::Write}; ProcessBreakConditions(false, _cpuDebugger->GetBreakpointManager(), operation, addressInfo); } void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { - AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation { addr, value, MemoryOperationType::Read }; - - BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy ? _gbDebugger->GetBreakpointManager() : _cpuDebugger->GetBreakpointManager(); + AddressInfo addressInfo{addr, memoryType}; + MemoryOperationInfo operation{addr, value, MemoryOperationType::Read}; + + BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy + ? _gbDebugger->GetBreakpointManager() + : _cpuDebugger->GetBreakpointManager(); ProcessBreakConditions(false, bpManager, operation, addressInfo); _memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock()); @@ -204,113 +240,145 @@ void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memor void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { - AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation { addr, value, MemoryOperationType::Write }; - - BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy ? _gbDebugger->GetBreakpointManager() : _cpuDebugger->GetBreakpointManager(); + AddressInfo addressInfo{addr, memoryType}; + MemoryOperationInfo operation{addr, value, MemoryOperationType::Write}; + + BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy + ? _gbDebugger->GetBreakpointManager() + : _cpuDebugger->GetBreakpointManager(); ProcessBreakConditions(false, bpManager, operation, addressInfo); _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _console->GetMasterClock()); } -template +template void Debugger::ProcessPpuCycle() { uint16_t scanline; uint16_t cycle; - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { scanline = _gameboy->GetPpu()->GetScanline(); cycle = _gameboy->GetPpu()->GetCycle(); - } else { + } + else + { scanline = _ppu->GetScanline(); cycle = _memoryManager->GetHClock(); } _ppuTools->UpdateViewers(scanline, cycle, cpuType); - switch(cpuType) { - case CpuType::Cpu: - //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) - if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { - _spc->Run(); - } else if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { - _cart->RunCoprocessors(); - } + switch (cpuType) + { + case CpuType::Cpu: + //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) + if (_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { + _spc->Run(); + } + else if (_traceLogger->IsCpuLogged(CpuType::NecDsp)) + { + _cart->RunCoprocessors(); + } - _cpuDebugger->ProcessPpuCycle(scanline, cycle); - break; + _cpuDebugger->ProcessPpuCycle(scanline, cycle); + break; - case CpuType::Gameboy: - _gbDebugger->ProcessPpuCycle(scanline, cycle); - break; + case CpuType::Gameboy: + _gbDebugger->ProcessPpuCycle(scanline, cycle); + break; } - if(_breakRequestCount > 0) { + if (_breakRequestCount > 0) + { SleepUntilResume(BreakSource::Unspecified); } } -void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId) +void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo* operation, int breakpointId) { - if(_suspendRequestCount) { + if (_suspendRequestCount) + { return; } _console->GetSoundMixer()->StopAudio(); _disassembler->Disassemble(CpuType::Cpu); _disassembler->Disassemble(CpuType::Spc); - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { _disassembler->Disassemble(CpuType::Sa1); - } else if(_cart->GetGsu()) { + } + else if (_cart->GetGsu()) + { _disassembler->Disassemble(CpuType::Gsu); - } else if(_cart->GetDsp()) { + } + else if (_cart->GetDsp()) + { _disassembler->Disassemble(CpuType::NecDsp); - } else if(_cart->GetCx4()) { + } + else if (_cart->GetCx4()) + { _disassembler->Disassemble(CpuType::Cx4); - } else if(_cart->GetGameboy()) { + } + else if (_cart->GetGameboy()) + { _disassembler->RefreshDisassembly(CpuType::Gameboy); } _executionStopped = true; - - if(source != BreakSource::Unspecified || _breakRequestCount == 0) { + + if (source != BreakSource::Unspecified || _breakRequestCount == 0) + { //Only trigger code break event if the pause was caused by user action BreakEvent evt = {}; evt.BreakpointId = breakpointId; evt.Source = source; - if(operation) { + if (operation) + { evt.Operation = *operation; } _waitForBreakResume = true; _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, &evt); } - while((_waitForBreakResume && !_suspendRequestCount) || _breakRequestCount) { + while ((_waitForBreakResume && !_suspendRequestCount) || _breakRequestCount) + { std::this_thread::sleep_for(std::chrono::duration(10)); } _executionStopped = false; } -void Debugger::ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source) +void Debugger::ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo& operation, + AddressInfo& addressInfo, BreakSource source) { - if(needBreak || _breakRequestCount || _waitForBreakResume) { + if (needBreak || _breakRequestCount || _waitForBreakResume) + { SleepUntilResume(source); - } else { + } + else + { int breakpointId = bpManager->CheckBreakpoint(operation, addressInfo); - if(breakpointId >= 0) { + if (breakpointId >= 0) + { SleepUntilResume(BreakSource::Breakpoint, &operation, breakpointId); } } } -template +template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; - case CpuType::Sa1: _sa1Debugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; - case CpuType::Gameboy: _gbDebugger->ProcessInterrupt(originalPc, currentPc); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessInterrupt(originalPc, currentPc, forNmi); + break; + case CpuType::Sa1: _sa1Debugger->ProcessInterrupt(originalPc, currentPc, forNmi); + break; + case CpuType::Gameboy: _gbDebugger->ProcessInterrupt(originalPc, currentPc); + break; } ProcessEvent(forNmi ? EventType::Nmi : EventType::Irq); @@ -320,46 +388,54 @@ void Debugger::ProcessEvent(EventType type) { _scriptManager->ProcessEvent(type); - switch(type) { - default: break; + switch (type) + { + default: break; - case EventType::StartFrame: - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Cpu); - GetEventManager(CpuType::Cpu)->ClearFrameEvents(); - break; + case EventType::StartFrame: + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, + (void*)CpuType::Cpu); + GetEventManager(CpuType::Cpu)->ClearFrameEvents(); + break; - case EventType::GbStartFrame: - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { - _scriptManager->ProcessEvent(EventType::StartFrame); - } - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Gameboy); - GetEventManager(CpuType::Gameboy)->ClearFrameEvents(); - break; - - case EventType::GbEndFrame: - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { - _scriptManager->ProcessEvent(EventType::EndFrame); - } - break; + case EventType::GbStartFrame: + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { + _scriptManager->ProcessEvent(EventType::StartFrame); + } + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, + (void*)CpuType::Gameboy); + GetEventManager(CpuType::Gameboy)->ClearFrameEvents(); + break; - case EventType::Reset: - Reset(); - break; + case EventType::GbEndFrame: + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { + _scriptManager->ProcessEvent(EventType::EndFrame); + } + break; - case EventType::StateLoaded: - _memoryAccessCounter->ResetCounts(); - break; + case EventType::Reset: + Reset(); + break; + + case EventType::StateLoaded: + _memoryAccessCounter->ResetCounts(); + break; } } -int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache) +int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType& resultType, bool useCache) { - MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read }; + MemoryOperationInfo operationInfo{0, 0, MemoryOperationType::Read}; DebugState state; GetState(state, false); - if(useCache) { + if (useCache) + { return _watchExpEval[(int)cpuType]->Evaluate(expression, state, resultType, operationInfo); - } else { + } + else + { ExpressionEvaluator expEval(this, cpuType); return expEval.Evaluate(expression, state, resultType, operationInfo); } @@ -369,19 +445,24 @@ void Debugger::Run() { _cpuDebugger->Run(); _spcDebugger->Run(); - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->Run(); } - if(_gsuDebugger) { + if (_gsuDebugger) + { _gsuDebugger->Run(); } - if(_necDspDebugger) { + if (_necDspDebugger) + { _necDspDebugger->Run(); } - if(_cx4Debugger) { + if (_cx4Debugger) + { _cx4Debugger->Run(); - } - if(_gbDebugger) { + } + if (_gbDebugger) + { _gbDebugger->Run(); } _waitForBreakResume = false; @@ -391,41 +472,57 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type) { DebugBreakHelper helper(this); StepRequest step; - IDebugger *debugger = nullptr; + IDebugger* debugger = nullptr; - switch(cpuType) { - case CpuType::Cpu: debugger = _cpuDebugger.get(); break; - case CpuType::Spc: debugger = _spcDebugger.get(); break; - case CpuType::NecDsp: debugger = _necDspDebugger.get(); break; - case CpuType::Sa1: debugger = _sa1Debugger.get(); break; - case CpuType::Gsu: debugger = _gsuDebugger.get(); break; - case CpuType::Cx4: debugger = _cx4Debugger.get(); break; - case CpuType::Gameboy: debugger = _gbDebugger.get(); break; + switch (cpuType) + { + case CpuType::Cpu: debugger = _cpuDebugger.get(); + break; + case CpuType::Spc: debugger = _spcDebugger.get(); + break; + case CpuType::NecDsp: debugger = _necDspDebugger.get(); + break; + case CpuType::Sa1: debugger = _sa1Debugger.get(); + break; + case CpuType::Gsu: debugger = _gsuDebugger.get(); + break; + case CpuType::Cx4: debugger = _cx4Debugger.get(); + break; + case CpuType::Gameboy: debugger = _gbDebugger.get(); + break; } - if(debugger) { + if (debugger) + { debugger->Step(stepCount, type); } - if(debugger != _cpuDebugger.get()) { + if (debugger != _cpuDebugger.get()) + { _cpuDebugger->Run(); } - if(debugger != _spcDebugger.get()) { + if (debugger != _spcDebugger.get()) + { _spcDebugger->Run(); } - if(_sa1Debugger && debugger != _sa1Debugger.get()) { + if (_sa1Debugger && debugger != _sa1Debugger.get()) + { _sa1Debugger->Run(); } - if(_gsuDebugger && debugger != _gsuDebugger.get()) { + if (_gsuDebugger && debugger != _gsuDebugger.get()) + { _gsuDebugger->Run(); } - if(_necDspDebugger && debugger != _necDspDebugger.get()) { + if (_necDspDebugger && debugger != _necDspDebugger.get()) + { _necDspDebugger->Run(); } - if(_cx4Debugger && debugger != _cx4Debugger.get()) { + if (_cx4Debugger && debugger != _cx4Debugger.get()) + { _cx4Debugger->Run(); } - if(_gbDebugger && debugger != _gbDebugger.get()) { + if (_gbDebugger && debugger != _gbDebugger.get()) + { _gbDebugger->Run(); } _waitForBreakResume = false; @@ -443,24 +540,33 @@ bool Debugger::HasBreakRequest() void Debugger::BreakRequest(bool release) { - if(release) { + if (release) + { _breakRequestCount--; - } else { + } + else + { _breakRequestCount++; } } void Debugger::SuspendDebugger(bool release) { - if(release) { - if(_suspendRequestCount > 0) { + if (release) + { + if (_suspendRequestCount > 0) + { _suspendRequestCount--; - } else { - #ifdef _DEBUG - //throw std::runtime_error("unexpected debugger suspend::release call"); - #endif } - } else { + else + { +#ifdef _DEBUG + //throw std::runtime_error("unexpected debugger suspend::release call"); +#endif + } + } + else + { _suspendRequestCount++; } } @@ -468,17 +574,25 @@ void Debugger::SuspendDebugger(bool release) void Debugger::BreakImmediately(BreakSource source) { bool gbDebugger = _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled); - if(source == BreakSource::GbDisableLcdOutsideVblank && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnDisableLcdOutsideVblank))) { + if (source == BreakSource::GbDisableLcdOutsideVblank && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnDisableLcdOutsideVblank))) + { return; - } else if(source == BreakSource::GbInvalidVramAccess && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidVramAccess))) { + } + else if (source == BreakSource::GbInvalidVramAccess && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnInvalidVramAccess))) + { return; - } else if(source == BreakSource::GbInvalidOamAccess && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOamAccess))) { + } + else if (source == BreakSource::GbInvalidOamAccess && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnInvalidOamAccess))) + { return; } SleepUntilResume(source); } -void Debugger::GetState(DebugState &state, bool partialPpuState) +void Debugger::GetState(DebugState& state, bool partialPpuState) { state.MasterClock = _console->GetMasterClock(); state.Cpu = _cpu->GetState(); @@ -486,27 +600,34 @@ void Debugger::GetState(DebugState &state, bool partialPpuState) state.Spc = _spc->GetState(); state.Dsp = _spc->GetDspState(); - if(!partialPpuState) { - for(int i = 0; i < 8; i++) { + if (!partialPpuState) + { + for (int i = 0; i < 8; i++) + { state.DmaChannels[i] = _dmaController->GetChannelConfig(i); } state.InternalRegs = _internalRegs->GetState(); state.Alu = _internalRegs->GetAluState(); } - if(_cart->GetDsp()) { + if (_cart->GetDsp()) + { state.NecDsp = _cart->GetDsp()->GetState(); } - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { state.Sa1 = _cart->GetSa1()->GetState(); } - if(_cart->GetGsu()) { + if (_cart->GetGsu()) + { state.Gsu = _cart->GetGsu()->GetState(); } - if(_cart->GetCx4()) { + if (_cart->GetCx4()) + { state.Cx4 = _cart->GetCx4()->GetState(); } - if(_cart->GetGameboy()) { + if (_cart->GetGameboy()) + { state.Gameboy = _cart->GetGameboy()->GetState(); } } @@ -558,23 +679,39 @@ void Debugger::SetSpcRegister(SpcRegister reg, uint16_t value) AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) { - if(relAddress.Type == SnesMemoryType::CpuMemory) { - if(_memoryManager->IsRegister(relAddress.Address)) { - return { relAddress.Address & 0xFFFF, SnesMemoryType::Register }; - } else { + if (relAddress.Type == SnesMemoryType::CpuMemory) + { + if (_memoryManager->IsRegister(relAddress.Address)) + { + return {relAddress.Address & 0xFFFF, SnesMemoryType::Register}; + } + else + { return _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); } - } else if(relAddress.Type == SnesMemoryType::SpcMemory) { + } + else if (relAddress.Type == SnesMemoryType::SpcMemory) + { return _spc->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::Sa1Memory) { + } + else if (relAddress.Type == SnesMemoryType::Sa1Memory) + { return _cart->GetSa1()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::GsuMemory) { + } + else if (relAddress.Type == SnesMemoryType::GsuMemory) + { return _cart->GetGsu()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::Cx4Memory) { + } + else if (relAddress.Type == SnesMemoryType::Cx4Memory) + { return _cart->GetCx4()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::NecDspMemory) { - return { relAddress.Address, SnesMemoryType::DspProgramRom }; - } else if(relAddress.Type == SnesMemoryType::GameboyMemory) { + } + else if (relAddress.Type == SnesMemoryType::NecDspMemory) + { + return {relAddress.Address, SnesMemoryType::DspProgramRom}; + } + else if (relAddress.Type == SnesMemoryType::GameboyMemory) + { return _cart->GetGameboy()->GetAbsoluteAddress(relAddress.Address); } @@ -584,64 +721,80 @@ AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) AddressInfo Debugger::GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) { MemoryMappings* mappings = nullptr; - switch(cpuType) { - case CpuType::Cpu: mappings = _memoryManager->GetMemoryMappings(); break; - case CpuType::Spc: break; - case CpuType::NecDsp: break; - case CpuType::Sa1: mappings = _cart->GetSa1()->GetMemoryMappings(); break; - case CpuType::Gsu: mappings = _cart->GetGsu()->GetMemoryMappings(); break; - case CpuType::Cx4: mappings = _cart->GetCx4()->GetMemoryMappings(); break; - case CpuType::Gameboy: break; + switch (cpuType) + { + case CpuType::Cpu: mappings = _memoryManager->GetMemoryMappings(); + break; + case CpuType::Spc: break; + case CpuType::NecDsp: break; + case CpuType::Sa1: mappings = _cart->GetSa1()->GetMemoryMappings(); + break; + case CpuType::Gsu: mappings = _cart->GetGsu()->GetMemoryMappings(); + break; + case CpuType::Cx4: mappings = _cart->GetCx4()->GetMemoryMappings(); + break; + case CpuType::Gameboy: break; } - switch(absAddress.Type) { - case SnesMemoryType::PrgRom: - case SnesMemoryType::WorkRam: - case SnesMemoryType::SaveRam: { - if(!mappings) { + switch (absAddress.Type) + { + case SnesMemoryType::PrgRom: + case SnesMemoryType::WorkRam: + case SnesMemoryType::SaveRam: + { + if (!mappings) + { throw std::runtime_error("Unsupported cpu type"); } uint8_t startBank = 0; //Try to find a mirror close to where the PC is - if(cpuType == CpuType::Cpu) { - if(absAddress.Type == SnesMemoryType::WorkRam) { + if (cpuType == CpuType::Cpu) + { + if (absAddress.Type == SnesMemoryType::WorkRam) + { startBank = 0x7E; - } else { + } + else + { startBank = _cpu->GetState().K & 0xC0; } - } else if(cpuType == CpuType::Sa1) { + } + else if (cpuType == CpuType::Sa1) + { startBank = (_cart->GetSa1()->GetCpuState().K & 0xC0); - } else if(cpuType == CpuType::Gsu) { + } + else if (cpuType == CpuType::Gsu) + { startBank = (_cart->GetGsu()->GetState().ProgramBank & 0xC0); } - return { mappings->GetRelativeAddress(absAddress, startBank), DebugUtilities::GetCpuMemoryType(cpuType) }; + return {mappings->GetRelativeAddress(absAddress, startBank), DebugUtilities::GetCpuMemoryType(cpuType)}; } - case SnesMemoryType::SpcRam: - case SnesMemoryType::SpcRom: - return { _spc->GetRelativeAddress(absAddress), SnesMemoryType::SpcMemory }; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - return { _cart->GetGameboy()->GetRelativeAddress(absAddress), SnesMemoryType::GameboyMemory }; + case SnesMemoryType::SpcRam: + case SnesMemoryType::SpcRom: + return {_spc->GetRelativeAddress(absAddress), SnesMemoryType::SpcMemory}; - case SnesMemoryType::DspProgramRom: - return { absAddress.Address, SnesMemoryType::NecDspMemory }; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + return {_cart->GetGameboy()->GetRelativeAddress(absAddress), SnesMemoryType::GameboyMemory}; - case SnesMemoryType::Register: - return { absAddress.Address & 0xFFFF, SnesMemoryType::Register }; + case SnesMemoryType::DspProgramRom: + return {absAddress.Address, SnesMemoryType::NecDspMemory}; - default: - return { -1, SnesMemoryType::Register }; + case SnesMemoryType::Register: + return {absAddress.Address & 0xFFFF, SnesMemoryType::Register}; + + default: + return {-1, SnesMemoryType::Register}; } } -void Debugger::SetCdlData(CpuType cpuType, uint8_t *cdlData, uint32_t length) +void Debugger::SetCdlData(CpuType cpuType, uint8_t* cdlData, uint32_t length) { DebugBreakHelper helper(this); GetCodeDataLogger(cpuType)->SetCdlData(cdlData, length); @@ -665,7 +818,8 @@ void Debugger::RefreshCodeCache() void Debugger::RebuildPrgCache(CpuType cpuType) { shared_ptr cdl = GetCodeDataLogger(cpuType); - if(!cdl) { + if (!cdl) + { return; } @@ -673,8 +827,10 @@ void Debugger::RebuildPrgCache(CpuType cpuType) AddressInfo addrInfo; addrInfo.Type = cpuType == CpuType::Gameboy ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; - for(uint32_t i = 0; i < prgRomSize; i++) { - if(cdl->IsCode(i)) { + for (uint32_t i = 0; i < prgRomSize; i++) + { + if (cdl->IsCode(i)) + { addrInfo.Address = (int32_t)i; i += _disassembler->BuildCache(addrInfo, cdl->GetCpuFlags(i), cdl->GetCpuType(i)) - 1; } @@ -685,14 +841,18 @@ void Debugger::GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memor { CpuType cpuType = DebugUtilities::ToCpuType(memoryType); shared_ptr cdl = GetCodeDataLogger(cpuType); - if(memoryType == SnesMemoryType::PrgRom || memoryType == SnesMemoryType::GbPrgRom) { + if (memoryType == SnesMemoryType::PrgRom || memoryType == SnesMemoryType::GbPrgRom) + { cdl->GetCdlData(offset, length, cdlData); - } else { + } + else + { SnesMemoryType prgType = _gbDebugger ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; AddressInfo relAddress; relAddress.Type = memoryType; - for(uint32_t i = 0; i < length; i++) { + for (uint32_t i = 0; i < length; i++) + { relAddress.Address = offset + i; AddressInfo info = GetAbsoluteAddress(relAddress); cdlData[i] = info.Type == prgType ? cdl->GetFlags(info.Address) : 0; @@ -704,60 +864,82 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { _cpuDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); _spcDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); - if(_gsuDebugger) { + if (_gsuDebugger) + { _gsuDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_necDspDebugger) { + if (_necDspDebugger) + { _necDspDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_cx4Debugger) { + if (_cx4Debugger) + { _cx4Debugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_gbDebugger) { + if (_gbDebugger) + { _gbDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } } void Debugger::GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes) { - switch (cpuType) { + switch (cpuType) + { case CpuType::Cpu: return _cpuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); case CpuType::Spc: return _spcDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); - case CpuType::Gsu: { - if (_gsuDebugger) { - return _gsuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + case CpuType::Gsu: + { + if (_gsuDebugger) + { + return _gsuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Sa1: { - if (_sa1Debugger) { - return _sa1Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Sa1: + { + if (_sa1Debugger) + { + return _sa1Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::NecDsp: { - if (_necDspDebugger) { - return _necDspDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::NecDsp: + { + if (_necDspDebugger) + { + return _necDspDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Cx4: { - if (_cx4Debugger) { - return _cx4Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Cx4: + { + if (_cx4Debugger) + { + return _cx4Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Gameboy: { - if (_gbDebugger) { - return _gbDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Gameboy: + { + if (_gbDebugger) + { + return _gbDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; + break; } } void Debugger::Log(string message) { auto lock = _logLock.AcquireSafe(); - if(_debuggerLog.size() >= 1000) { + if (_debuggerLog.size() >= 1000) + { _debuggerLog.pop_front(); } _debuggerLog.push_back(message); @@ -767,7 +949,8 @@ string Debugger::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string& msg : _debuggerLog) { + for (string& msg : _debuggerLog) + { ss << msg << "\n"; } return ss.str(); @@ -780,25 +963,35 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str Gameboy* gb = _cart->GetGameboy(); vector rom; - if(gb) { + if (gb) + { uint8_t* prgRom = gb->DebugGetMemory(SnesMemoryType::GbPrgRom); uint32_t prgRomSize = gb->DebugGetMemorySize(SnesMemoryType::GbPrgRom); - rom = vector(prgRom, prgRom+prgRomSize); - } else { + rom = vector(prgRom, prgRom + prgRomSize); + } + else + { rom = vector(_cart->DebugGetPrgRom(), _cart->DebugGetPrgRom() + _cart->DebugGetPrgRomSize()); } - if(saveAsIps) { + if (saveAsIps) + { output = IpsPatcher::CreatePatch(_cart->GetOriginalPrgRom(), rom); - } else { - if(stripOption != CdlStripOption::StripNone) { + } + else + { + if (stripOption != CdlStripOption::StripNone) + { GetCodeDataLogger(gb ? CpuType::Gameboy : CpuType::Cpu)->StripData(rom.data(), stripOption); //Preserve rom header regardless of CDL file contents - if(gb) { + if (gb) + { GameboyHeader header = gb->GetHeader(); memcpy(rom.data() + romInfo.HeaderOffset, &header, sizeof(GameboyHeader)); - } else { + } + else + { memcpy(rom.data() + romInfo.HeaderOffset, &romInfo.Header, sizeof(SnesCartInformation)); } } @@ -806,7 +999,8 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str } ofstream file(filename, ios::out | ios::binary); - if(file) { + if (file) + { file.write((char*)output.data(), output.size()); file.close(); } @@ -829,9 +1023,12 @@ shared_ptr Debugger::GetMemoryAccessCounter() shared_ptr Debugger::GetCodeDataLogger(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return _gbDebugger ? _gbDebugger->GetCodeDataLogger() : nullptr; - } else { + } + else + { return _codeDataLogger; } } @@ -848,9 +1045,12 @@ shared_ptr Debugger::GetPpuTools() shared_ptr Debugger::GetEventManager(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return std::dynamic_pointer_cast(_gbDebugger->GetEventManager()); - } else { + } + else + { return std::dynamic_pointer_cast(_cpuDebugger->GetEventManager()); } } @@ -867,16 +1067,17 @@ shared_ptr Debugger::GetScriptManager() shared_ptr Debugger::GetCallstackManager(CpuType cpuType) { - switch(cpuType) { - case CpuType::Cpu: return _cpuDebugger->GetCallstackManager(); - case CpuType::Spc: return _spcDebugger->GetCallstackManager(); - case CpuType::Sa1: return _sa1Debugger->GetCallstackManager(); - case CpuType::Gameboy: return _gbDebugger->GetCallstackManager(); + switch (cpuType) + { + case CpuType::Cpu: return _cpuDebugger->GetCallstackManager(); + case CpuType::Spc: return _spcDebugger->GetCallstackManager(); + case CpuType::Sa1: return _sa1Debugger->GetCallstackManager(); + case CpuType::Gameboy: return _gbDebugger->GetCallstackManager(); - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - break; + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + break; } throw std::runtime_error("GetCallstackManager() - Unsupported CPU type"); } @@ -888,9 +1089,12 @@ shared_ptr Debugger::GetConsole() shared_ptr Debugger::GetAssembler(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return std::dynamic_pointer_cast(_gbDebugger->GetAssembler()); - } else { + } + else + { return std::dynamic_pointer_cast(_cpuDebugger->GetAssembler()); } } diff --git a/Core/Debugger.h b/Core/Debugger.h index 4d6f494..0dcbf0a 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -75,7 +75,7 @@ private: shared_ptr _labelManager; unique_ptr _watchExpEval[(int)DebugUtilities::GetLastCpuType() + 1]; - + SimpleLock _logLock; std::list _debuggerLog; @@ -84,7 +84,7 @@ private: atomic _suspendRequestCount; bool _waitForBreakResume = false; - + void Reset(); public: @@ -92,10 +92,10 @@ public: ~Debugger(); void Release(); - template + template void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); - - template + + template 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 + template void ProcessPpuCycle(); - template + template 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,7 +124,8 @@ 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); @@ -143,15 +144,15 @@ 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(); void RebuildPrgCache(CpuType cpuType); void SetBreakpoints(Breakpoint breakpoints[], uint32_t length); void GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes); - + void Log(string message); string GetLog(); diff --git a/Core/DefaultVideoFilter.cpp b/Core/DefaultVideoFilter.cpp index ad729c5..64b33a2 100644 --- a/Core/DefaultVideoFilter.cpp +++ b/Core/DefaultVideoFilter.cpp @@ -20,14 +20,15 @@ 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; @@ -42,24 +43,29 @@ 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; @@ -74,7 +80,9 @@ 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; } } @@ -89,11 +97,14 @@ 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; } @@ -111,63 +122,82 @@ 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(); - + int overscanMultiplier = _baseFrameInfo.Width == 512 ? 2 : 1; uint32_t width = _baseFrameInfo.Width; uint32_t xOffset = overscan.Left * overscanMultiplier; 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]]; } } @@ -177,16 +207,16 @@ 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))); b = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[4] * i + _yiqToRgbMatrix[5] * q))); -} \ No newline at end of file +} diff --git a/Core/DefaultVideoFilter.h b/Core/DefaultVideoFilter.h index 0bae98d..09e4a93 100644 --- a/Core/DefaultVideoFilter.h +++ b/Core/DefaultVideoFilter.h @@ -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); - void ApplyFilter(uint16_t *ppuOutputBuffer); + void ApplyFilter(uint16_t* ppuOutputBuffer); static uint32_t ToArgb(uint16_t rgb555); -}; \ No newline at end of file +}; diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index 6f1e50d..635f278 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -46,18 +46,21 @@ Disassembler::Disassembler(shared_ptr console, shared_ptrGetMemoryDumper().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(); _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); } } @@ -67,42 +70,49 @@ void Disassembler::InitSource(SnesMemoryType type) uint8_t* src = _memoryDumper->GetMemoryBuffer(type); uint32_t size = _memoryDumper->GetMemorySize(type); _disassemblyCache[(int)type] = vector(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; } @@ -111,7 +121,8 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy address += disInfo.GetOpSize(); } - if(needDisassemble) { + if (needDisassemble) + { SetDisassembleFlag(type); } @@ -120,12 +131,15 @@ 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; } } @@ -146,85 +160,97 @@ 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; } } } } - - if(needDisassemble) { + + if (needDisassemble) + { SetDisassembleFlag(type); } } void Disassembler::Disassemble(CpuType cpuType) { - if(!_needDisassemble[(int)cpuType]) { + if (!_needDisassemble[(int)cpuType]) + { return; } _needDisassemble[(int)cpuType] = false; - auto lock = _disassemblyLock.AcquireSafe(); - - MemoryMappings *mappings = nullptr; + auto lock = _disassemblyLock.AcquireSafe(); + + MemoryMappings* mappings = nullptr; int32_t maxAddr = 0xFFFFFF; - switch(cpuType) { - case CpuType::Cpu: - mappings = _memoryManager->GetMemoryMappings(); - break; + switch (cpuType) + { + case CpuType::Cpu: + mappings = _memoryManager->GetMemoryMappings(); + break; - case CpuType::Sa1: - if(!_sa1) { - return; - } - mappings = _sa1->GetMemoryMappings(); - break; + case CpuType::Sa1: + if (!_sa1) + { + return; + } + mappings = _sa1->GetMemoryMappings(); + break; - case CpuType::Gsu: - if(!_gsu) { - return; - } - mappings = _gsu->GetMemoryMappings(); - break; + case CpuType::Gsu: + if (!_gsu) + { + return; + } + mappings = _gsu->GetMemoryMappings(); + break; - case CpuType::NecDsp: - if(!_console->GetCartridge()->GetDsp()) { - return; - } - mappings = nullptr; - maxAddr = _necDsp->DebugGetProgramRomSize() - 1; - break; + case CpuType::NecDsp: + if (!_console->GetCartridge()->GetDsp()) + { + return; + } + mappings = nullptr; + maxAddr = _necDsp->DebugGetProgramRomSize() - 1; + break; - case CpuType::Spc: - mappings = nullptr; - maxAddr = 0xFFFF; - break; + case CpuType::Spc: + mappings = nullptr; + maxAddr = 0xFFFF; + break; - case CpuType::Gameboy: - if(!_gameboy) { - return; - } - mappings = nullptr; - maxAddr = 0xFFFF; - break; + case CpuType::Gameboy: + if (!_gameboy) + { + return; + } + mappings = nullptr; + maxAddr = 0xFFFF; + break; - case CpuType::Cx4: - if(!_console->GetCartridge()->GetCx4()) { - return; - } - mappings = _console->GetCartridge()->GetCx4()->GetMemoryMappings(); - break; + case CpuType::Cx4: + if (!_console->GetCartridge()->GetCx4()) + { + return; + } + mappings = _console->GetCartridge()->GetCx4()->GetMemoryMappings(); + break; - default: throw std::runtime_error("Disassemble(): Invalid cpu type"); + default: throw std::runtime_error("Disassemble(): Invalid cpu type"); } - vector &results = _disassemblyResult[(int)cpuType]; + vector& results = _disassemblyResult[(int)cpuType]; results.clear(); bool disUnident = _settings->CheckDebuggerFlag(DebuggerFlags::DisassembleUnidentifiedData); @@ -238,54 +264,73 @@ 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; } DisassemblerSource src = GetSource(addrInfo.Type); DisassemblyInfo disassemblyInfo = (*src.Cache)[addrInfo.Address]; - + uint8_t opSize = 0; uint8_t opCode = (src.Data + addrInfo.Address)[0]; 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++; } @@ -293,42 +338,62 @@ 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; @@ -336,29 +401,45 @@ 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))); } @@ -366,16 +447,19 @@ 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; @@ -400,14 +484,20 @@ uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress) auto lock = _disassemblyLock.AcquireSafe(); vector& 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; } @@ -416,53 +506,68 @@ 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& 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) { - default: break; - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break; + switch (result.Address.Type) + { + default: break; + case SnesMemoryType::GbPrgRom: + 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::GbCartRam: - case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break; + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; + break; + + case SnesMemoryType::GbCartRam: + 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)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)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; @@ -470,88 +575,119 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d data.Address = result.CpuAddress; data.AbsoluteAddress = result.Address.Address; - switch(lineCpuType) { - case CpuType::Cpu: - case CpuType::Sa1: { + switch (lineCpuType) + { + case CpuType::Cpu: + 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; } - - case CpuType::NecDsp: - case CpuType::Cx4: - if(!disInfo.IsInitialized()) { - disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, type); - } else { - data.Flags |= LineFlags::VerifiedCode; - } - data.OpSize = disInfo.GetOpSize(); - data.EffectiveAddress = -1; - data.ValueSize = 0; - break; + case CpuType::NecDsp: + case CpuType::Cx4: + if (!disInfo.IsInitialized()) + { + disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, type); + } + else + { + data.Flags |= LineFlags::VerifiedCode; + } - case CpuType::Gameboy: { + data.OpSize = disInfo.GetOpSize(); + data.EffectiveAddress = -1; + data.ValueSize = 0; + break; + + 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; } @@ -568,27 +704,38 @@ 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)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; @@ -600,25 +747,31 @@ 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& 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); } } diff --git a/Core/Disassembler.h b/Core/Disassembler.h index a84a092..799512b 100644 --- a/Core/Disassembler.h +++ b/Core/Disassembler.h @@ -24,16 +24,16 @@ enum class CpuType : uint8_t; struct DisassemblerSource { - uint8_t *Data; - vector *Cache; + uint8_t* Data; + vector* 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 _cdl; shared_ptr _labelManager; - MemoryDumper *_memoryDumper; + MemoryDumper* _memoryDumper; DisassemblerSource _sources[(int)SnesMemoryType::Register] = {}; vector _disassemblyCache[(int)SnesMemoryType::Register]; SimpleLock _disassemblyLock; - vector _disassemblyResult[(int)DebugUtilities::GetLastCpuType()+1]; - bool _needDisassemble[(int)DebugUtilities::GetLastCpuType()+1]; + vector _disassemblyResult[(int)DebugUtilities::GetLastCpuType() + 1]; + bool _needDisassemble[(int)DebugUtilities::GetLastCpuType() + 1]; void InitSource(SnesMemoryType type); DisassemblerSource& GetSource(SnesMemoryType type); @@ -61,16 +61,17 @@ private: public: Disassembler(shared_ptr console, shared_ptr 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); -}; \ No newline at end of file + 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); +}; diff --git a/Core/DisassemblyInfo.cpp b/Core/DisassemblyInfo.cpp index 839f4f4..86fec52 100644 --- a/Core/DisassemblyInfo.cpp +++ b/Core/DisassemblyInfo.cpp @@ -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,8 +43,9 @@ 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; @@ -65,37 +66,45 @@ 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) { - case CpuType::Sa1: - case CpuType::Cpu: - CpuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); - break; + 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) { - case CpuType::Sa1: - case CpuType::Cpu: - return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState, cpuType); + switch (_cpuType) + { + case CpuType::Sa1: + case CpuType::Cpu: + return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState, cpuType); - case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState); - case CpuType::Gsu: return GsuDisUtils::GetEffectiveAddress(*this, console, *(GsuState*)cpuState); + case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState); + case CpuType::Gsu: return GsuDisUtils::GetEffectiveAddress(*this, console, *(GsuState*)cpuState); - case CpuType::Cx4: - case CpuType::NecDsp: - return -1; + case CpuType::Cx4: + case CpuType::NecDsp: + return -1; - case CpuType::Gameboy: return GameboyDisUtils::GetEffectiveAddress(*this, console, *(GbCpuState*)cpuState); + case CpuType::Gameboy: return GameboyDisUtils::GetEffectiveAddress(*this, console, *(GbCpuState*)cpuState); } return -1; } @@ -130,12 +139,14 @@ 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(' '); } } @@ -144,27 +155,33 @@ void DisassemblyInfo::GetByteCode(string &out) uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type) { - switch(type) { - case CpuType::Sa1: - case CpuType::Cpu: - return CpuDisUtils::GetOpSize(opCode, flags); + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return CpuDisUtils::GetOpSize(opCode, flags); - case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode); - - case CpuType::Gsu: - if(opCode >= 0x05 && opCode <= 0x0F) { - return 2; - } else if(opCode >= 0xA0 && opCode <= 0xAF) { - return 2; - } else if(opCode >= 0xF0 && opCode <= 0xFF) { - return 3; - } - return 1; + case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode); - case CpuType::NecDsp: return 3; - case CpuType::Cx4: return 2; - - case CpuType::Gameboy: return GameboyDisUtils::GetOpSize(opCode); + case CpuType::Gsu: + if (opCode >= 0x05 && opCode <= 0x0F) + { + return 2; + } + else if (opCode >= 0xA0 && opCode <= 0xAF) + { + return 2; + } + else if (opCode >= 0xF0 && opCode <= 0xFF) + { + return 3; + } + return 1; + + case CpuType::NecDsp: return 3; + case CpuType::Cx4: return 2; + + case CpuType::Gameboy: return GameboyDisUtils::GetOpSize(opCode); } return 0; } @@ -172,19 +189,20 @@ 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) { - case CpuType::Sa1: - case CpuType::Cpu: - return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL - case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK - - case CpuType::Gameboy: return GameboyDisUtils::IsJumpToSub(opCode); - - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - return false; + case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK + + case CpuType::Gameboy: return GameboyDisUtils::IsJumpToSub(opCode); + + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + return false; } return false; } @@ -192,52 +210,62 @@ bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type) bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type) { //RTS/RTI - switch(type) { - case CpuType::Sa1: - case CpuType::Cpu: - return opCode == 0x60 || opCode == 0x6B || opCode == 0x40; + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return opCode == 0x60 || opCode == 0x6B || opCode == 0x40; - case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F; + case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F; - case CpuType::Gameboy: return GameboyDisUtils::IsReturnInstruction(opCode); + case CpuType::Gameboy: return GameboyDisUtils::IsReturnInstruction(opCode); - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - return false; + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + return false; } - + return false; } bool DisassemblyInfo::IsUnconditionalJump() { uint8_t opCode = GetOpCode(); - 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) { - //Jumps, RTI, RTS, BRK, COP, etc., stop disassembling - return true; - } 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) { - return true; - } - return false; - - case CpuType::Gsu: - case CpuType::Spc: - case CpuType::Cx4: + 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) + { + //Jumps, RTI, RTS, BRK, COP, etc., stop disassembling return true; + } + else if (opCode == 0x28) + { + //PLP, stop disassembling because the 8-bit/16-bit flags could change + return true; + } + return false; - case CpuType::NecDsp: - 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) + { + return true; + } + return false; + + case CpuType::Gsu: + case CpuType::Spc: + case CpuType::Cx4: + return true; + + case CpuType::NecDsp: + return false; } return false; @@ -245,13 +273,17 @@ 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; @@ -259,12 +291,16 @@ 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); } diff --git a/Core/DisassemblyInfo.h b/Core/DisassemblyInfo.h index 2ee0cc9..ed5a281 100644 --- a/Core/DisassemblyInfo.h +++ b/Core/DisassemblyInfo.h @@ -20,16 +20,16 @@ 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(); uint8_t GetOpSize(); @@ -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); }; - diff --git a/Core/DmaController.cpp b/Core/DmaController.cpp index 3fa9217..0d6104b 100644 --- a/Core/DmaController.cpp +++ b/Core/DmaController.cpp @@ -5,19 +5,21 @@ #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); } } @@ -33,36 +35,47 @@ 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; } @@ -70,10 +83,11 @@ 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, @@ -81,14 +95,16 @@ 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; } @@ -97,31 +113,37 @@ 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; @@ -131,12 +153,14 @@ 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); @@ -146,7 +170,8 @@ bool DmaController::InitHdmaChannels() } } - if(needSync) { + if (needSync) + { SyncEndDma(); } @@ -154,15 +179,17 @@ 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]), @@ -170,9 +197,13 @@ 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]), @@ -180,7 +211,8 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel) ); channel.HdmaTableAddress++; i++; - } while(i < transferByteCount); + } + while (i < transferByteCount); } } @@ -195,13 +227,16 @@ 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; } } @@ -212,13 +247,15 @@ bool DmaController::ProcessHdmaChannels() { _hdmaPending = false; - if(!_hdmaChannels) { + if (!_hdmaChannels) + { UpdateNeedToProcessFlag(); return false; } bool needSync = !HasActiveDmaChannel(); - if(needSync) { + if (needSync) + { SyncStartDma(); } _memoryManager->IncMasterClock8(); @@ -226,20 +263,24 @@ 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); @@ -247,9 +288,11 @@ 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; } @@ -265,32 +308,38 @@ 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(); - + uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); _memoryManager->IncMasterClock4(); ch.TransferSize = (msb << 8) | lsb; - } + } } //"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; } @@ -299,7 +348,8 @@ bool DmaController::ProcessHdmaChannels() } } - if(needSync) { + if (needSync) + { //If we ran a HDMA transfer, sync SyncEndDma(); } @@ -312,8 +362,10 @@ 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; } } @@ -328,7 +380,8 @@ void DmaController::UpdateNeedToProcessFlag() void DmaController::BeginHdmaTransfer() { - if(_hdmaChannels) { + if (_hdmaChannels) + { _hdmaPending = true; UpdateNeedToProcessFlag(); } @@ -342,33 +395,42 @@ 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]); + RunDma(_channel[i]); } } - + SyncEndDma(); UpdateNeedToProcessFlag(); @@ -380,16 +442,21 @@ 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(); @@ -397,15 +464,22 @@ void DmaController::Write(uint16_t addr, uint8_t value) break; } - case 0x420C: - //HDMAEN - HDMA Enable - _hdmaChannels = value; - break; + case 0x420C: + //HDMAEN - HDMA Enable + _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; @@ -415,101 +489,192 @@ 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) | @@ -520,81 +685,164 @@ 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(); } @@ -609,10 +857,11 @@ 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, diff --git a/Core/DmaController.h b/Core/DmaController.h index 89ee10a..28feae2 100644 --- a/Core/DmaController.h +++ b/Core/DmaController.h @@ -18,17 +18,17 @@ private: uint8_t _hdmaChannels = 0; bool _dmaPending = false; uint64_t _dmaStartClock = 0; - + 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 RunHdmaTransfer(DmaChannelConfig &channel); + void RunDma(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; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/DmaControllerTypes.h b/Core/DmaControllerTypes.h index f673d82..c41648c 100644 --- a/Core/DmaControllerTypes.h +++ b/Core/DmaControllerTypes.h @@ -26,4 +26,4 @@ struct DmaChannelConfig bool UnusedFlag; uint8_t UnusedByte; // 43xB and 43xF -}; \ No newline at end of file +}; diff --git a/Core/DrawCommand.h b/Core/DrawCommand.h index ead95eb..4707672 100644 --- a/Core/DrawCommand.h +++ b/Core/DrawCommand.h @@ -18,34 +18,50 @@ 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); - } else { - _argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)] = 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 { - int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1)*_xScale) - (int)(x*_xScale); + else + { + _argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)] = color; + } + } + 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; } } } @@ -65,7 +81,7 @@ protected: public: DrawCommand(int startFrame, int frameCount, bool useIntegerScaling = false) - { + { _frameCount = frameCount > 0 ? frameCount : -1; _startFrame = startFrame; _useIntegerScaling = useIntegerScaling; @@ -75,9 +91,10 @@ public: { } - void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan, uint32_t lineWidth, uint32_t frameNumber) + void Draw(uint32_t* argbBuffer, OverscanDimensions& overscan, uint32_t lineWidth, uint32_t frameNumber) { - if(_startFrame <= frameNumber) { + if (_startFrame <= frameNumber) + { _argbBuffer = argbBuffer; _overscan = overscan; _lineWidth = lineWidth; diff --git a/Core/DrawLineCommand.h b/Core/DrawLineCommand.h index 28daaf7..7f1e156 100644 --- a/Core/DrawLineCommand.h +++ b/Core/DrawLineCommand.h @@ -16,18 +16,24 @@ 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; } } } diff --git a/Core/DrawRectangleCommand.h b/Core/DrawRectangleCommand.h index 2062626..f96fe36 100644 --- a/Core/DrawRectangleCommand.h +++ b/Core/DrawRectangleCommand.h @@ -11,18 +11,25 @@ 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); } @@ -33,11 +40,13 @@ 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; } @@ -45,4 +54,4 @@ public: //Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time) _color = (~color & 0xFF000000) | (color & 0xFFFFFF); } -}; \ No newline at end of file +}; diff --git a/Core/DrawScreenBufferCommand.h b/Core/DrawScreenBufferCommand.h index 2cff980..4f58986 100644 --- a/Core/DrawScreenBufferCommand.h +++ b/Core/DrawScreenBufferCommand.h @@ -5,13 +5,15 @@ 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]); } } diff --git a/Core/DrawStringCommand.h b/Core/DrawStringCommand.h index 6aea0a8..8f9f8e5 100644 --- a/Core/DrawStringCommand.h +++ b/Core/DrawStringCommand.h @@ -11,101 +11,101 @@ private: //Taken from FCEUX's LUA code const int _tabSpace = 4; const uint8_t _font[792] = { - 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, - 3, 64, 64, 0, 0, 0, 0, 0, + 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, + 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, - 3, 0, 0, 0, 0, 0, 0, 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, + 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, - 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, + 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, 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,24 +125,35 @@ 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; diff --git a/Core/DummyCpu.h b/Core/DummyCpu.h index 6cb7d81..3bd27da 100644 --- a/Core/DummyCpu.h +++ b/Core/DummyCpu.h @@ -16,7 +16,9 @@ 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; } @@ -33,7 +35,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; @@ -65,13 +67,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]; @@ -80,4 +82,4 @@ void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value) int32_t DummyCpu::GetLastOperand() { return _operand; -} \ No newline at end of file +} diff --git a/Core/DummySpc.h b/Core/DummySpc.h index 5e28dc7..aa74777 100644 --- a/Core/DummySpc.h +++ b/Core/DummySpc.h @@ -12,7 +12,7 @@ #include "Spc.h" -DummySpc::DummySpc(uint8_t *spcRam, SpcState &state) +DummySpc::DummySpc(uint8_t* spcRam, SpcState& state) { _ram = spcRam; @@ -37,9 +37,11 @@ DummySpc::~DummySpc() void DummySpc::Step() { - do { + do + { ProcessCycle(); - } while(_opStep != SpcOpStep::ReadOpCode); + } + while (_opStep != SpcOpStep::ReadOpCode); } uint32_t DummySpc::GetWriteCount() @@ -66,14 +68,14 @@ 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]; -} \ No newline at end of file +} diff --git a/Core/EmuSettings.cpp b/Core/EmuSettings.cpp index b6f8ed8..21022ac 100644 --- a/Core/EmuSettings.cpp +++ b/Core/EmuSettings.cpp @@ -31,15 +31,19 @@ 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(); @@ -70,14 +74,16 @@ 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); } @@ -85,8 +91,10 @@ 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; @@ -103,14 +111,20 @@ 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"); } @@ -177,11 +191,16 @@ void EmuSettings::SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCo { _emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination; - for(int i = 0; i < 3; i++) { - for(std::pair &kvp : _emulatorKeys[i]) { - if(keyCombination.IsSubsetOf(kvp.second)) { + for (int i = 0; i < 3; i++) + { + for (std::pair& 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); } } @@ -192,10 +211,14 @@ void EmuSettings::SetShortcutKeys(vector 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); } } @@ -204,7 +227,8 @@ void EmuSettings::SetShortcutKeys(vector 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 {}; @@ -218,13 +242,16 @@ vector 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; @@ -240,50 +267,63 @@ 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) { - 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; - case VideoAspectRatio::PAL: return 11.0 / 8.0; - case VideoAspectRatio::Standard: return 4.0 / 3.0; - case VideoAspectRatio::Widescreen: return 16.0 / 9.0; - case VideoAspectRatio::Custom: return _video.CustomAspectRatio; + 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; + case VideoAspectRatio::PAL: return 11.0 / 8.0; + case VideoAspectRatio::Standard: return 4.0 / 3.0; + case VideoAspectRatio::Widescreen: return 16.0 / 9.0; + case VideoAspectRatio::Custom: return _video.CustomAspectRatio; } return 0.0; } 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; } } @@ -295,12 +335,17 @@ 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; } } @@ -313,16 +358,20 @@ bool EmuSettings::CheckDebuggerFlag(DebuggerFlags flag) void EmuSettings::InitializeRam(void* data, uint32_t length) { - switch(_emulation.RamPowerOnState) { - default: - 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++) { - ((uint8_t*)data)[i] = dist(_mt); - } - break; + switch (_emulation.RamPowerOnState) + { + default: + 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++) + { + ((uint8_t*)data)[i] = dist(_mt); + } + break; } } @@ -333,8 +382,8 @@ int EmuSettings::GetRandomValue(int maxValue) } bool EmuSettings::GetRandomBool() -{ - return GetRandomValue(1) == 1; +{ + return GetRandomValue(1) == 1; } bool EmuSettings::IsInputEnabled() @@ -344,12 +393,13 @@ bool EmuSettings::IsInputEnabled() double EmuSettings::GetControllerDeadzoneRatio() { - switch(_input.ControllerDeadzoneSize) { - case 0: return 0.5; - case 1: return 0.75; - case 2: return 1; - case 3: return 1.25; - case 4: return 1.5; + switch (_input.ControllerDeadzoneSize) + { + case 0: return 0.5; + case 1: return 0.75; + case 2: return 1; + case 3: return 1.25; + case 4: return 1.5; } return 1; } diff --git a/Core/EmuSettings.h b/Core/EmuSettings.h index c951c6f..e3274d2 100644 --- a/Core/EmuSettings.h +++ b/Core/EmuSettings.h @@ -31,7 +31,7 @@ private: std::unordered_map _emulatorKeys[3]; std::unordered_map> _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); @@ -77,11 +77,11 @@ public: void SetDebuggerFlag(DebuggerFlags flag, bool enabled); bool CheckDebuggerFlag(DebuggerFlags flags); - + int GetRandomValue(int maxValue); bool GetRandomBool(); void InitializeRam(void* data, uint32_t length); bool IsInputEnabled(); double GetControllerDeadzoneRatio(); -}; \ No newline at end of file +}; diff --git a/Core/EventManager.cpp b/Core/EventManager.cpp index e2b807e..e216ede 100644 --- a/Core/EventManager.cpp +++ b/Core/EventManager.cpp @@ -10,7 +10,8 @@ #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; @@ -27,7 +28,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; @@ -36,10 +37,13 @@ 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; } @@ -57,14 +61,14 @@ void EventManager::AddEvent(DebugEventType type) evt.Cycle = _memoryManager->GetHClock(); evt.BreakpointId = -1; evt.DmaChannel = -1; - + CpuState state = _cpu->GetState(); evt.ProgramCounter = (state.K << 16) | state.PC; _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()); @@ -72,12 +76,14 @@ 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; } } @@ -100,120 +106,191 @@ void EventManager::ClearFrameEvents() _debugEvents.clear(); } -void EventManager::FilterEvents(EventViewerDisplayOptions &options) +void EventManager::FilterEvents(EventViewerDisplayOptions& options) { auto lock = _lock.AcquireSafe(); _sentEvents.clear(); vector 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; - case DebugEventType::Register: - 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) { - showEvent = options.ShowPpuRegisterOamWrites; - } else if(reg >= 0x2105 && reg <= 0x210C) { - showEvent = options.ShowPpuRegisterBgOptionWrites; - } else if(reg >= 0x210D && reg <= 0x2114) { - showEvent = options.ShowPpuRegisterBgScrollWrites; - } else if(reg >= 0x2115 && reg <= 0x2119) { - showEvent = options.ShowPpuRegisterVramWrites; - } else if(reg >= 0x211A && reg <= 0x2120) { - showEvent = options.ShowPpuRegisterMode7Writes; - } else if(reg >= 0x2121 && reg <= 0x2122) { - showEvent = options.ShowPpuRegisterCgramWrites; - } else if(reg >= 0x2123 && reg <= 0x212B) { - showEvent = options.ShowPpuRegisterWindowWrites; - } else { - showEvent = options.ShowPpuRegisterOtherWrites; - } - } else { - showEvent = options.ShowPpuRegisterReads; - } - } else if(reg <= 0x217F) { - showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; - } else if(reg <= 0x2183) { - showEvent = isWrite ? options.ShowWorkRamRegisterWrites : options.ShowWorkRamRegisterReads; - } else if(reg >= 0x4000) { - showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; - } + 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]) + { + showEvent = false; break; + } + + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg <= 0x213F) + { + if (isWrite) + { + if (reg >= 0x2101 && reg <= 0x2104) + { + showEvent = options.ShowPpuRegisterOamWrites; + } + else if (reg >= 0x2105 && reg <= 0x210C) + { + showEvent = options.ShowPpuRegisterBgOptionWrites; + } + else if (reg >= 0x210D && reg <= 0x2114) + { + showEvent = options.ShowPpuRegisterBgScrollWrites; + } + else if (reg >= 0x2115 && reg <= 0x2119) + { + showEvent = options.ShowPpuRegisterVramWrites; + } + else if (reg >= 0x211A && reg <= 0x2120) + { + showEvent = options.ShowPpuRegisterMode7Writes; + } + else if (reg >= 0x2121 && reg <= 0x2122) + { + showEvent = options.ShowPpuRegisterCgramWrites; + } + else if (reg >= 0x2123 && reg <= 0x212B) + { + showEvent = options.ShowPpuRegisterWindowWrites; + } + else + { + showEvent = options.ShowPpuRegisterOtherWrites; + } + } + else + { + showEvent = options.ShowPpuRegisterReads; + } + } + else if (reg <= 0x217F) + { + showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; + } + else if (reg <= 0x2183) + { + showEvent = isWrite ? options.ShowWorkRamRegisterWrites : options.ShowWorkRamRegisterReads; + } + 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; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg <= 0x213F) { - if(isWrite) { - if(reg >= 0x2101 && reg <= 0x2104) { - color = options.PpuRegisterWriteOamColor; - } else if(reg >= 0x2105 && reg <= 0x210C) { - color = options.PpuRegisterWriteBgOptionColor; - } else if(reg >= 0x210D && reg <= 0x2114) { - color = options.PpuRegisterWriteBgScrollColor; - } else if(reg >= 0x2115 && reg <= 0x2119) { - color = options.PpuRegisterWriteVramColor; - } else if(reg >= 0x211A && reg <= 0x2120) { - color = options.PpuRegisterWriteMode7Color; - } else if(reg >= 0x2121 && reg <= 0x2122) { - color = options.PpuRegisterWriteCgramColor; - } else if(reg >= 0x2123 && reg <= 0x212B) { - color = options.PpuRegisterWriteWindowColor; - } else { - color = options.PpuRegisterWriteOtherColor; - } - } else { - color = options.PpuRegisterReadColor; + 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) + { + color = options.PpuRegisterWriteOamColor; + } + else if (reg >= 0x2105 && reg <= 0x210C) + { + color = options.PpuRegisterWriteBgOptionColor; + } + else if (reg >= 0x210D && reg <= 0x2114) + { + color = options.PpuRegisterWriteBgScrollColor; + } + else if (reg >= 0x2115 && reg <= 0x2119) + { + color = options.PpuRegisterWriteVramColor; + } + else if (reg >= 0x211A && reg <= 0x2120) + { + color = options.PpuRegisterWriteMode7Color; + } + else if (reg >= 0x2121 && reg <= 0x2122) + { + color = options.PpuRegisterWriteCgramColor; + } + else if (reg >= 0x2123 && reg <= 0x212B) + { + color = options.PpuRegisterWriteWindowColor; + } + else + { + color = options.PpuRegisterWriteOtherColor; } - } else if(reg <= 0x217F) { - color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; - } else if(reg <= 0x2183) { - color = isWrite ? options.WorkRamRegisterWriteColor : options.WorkRamRegisterReadColor; - } else if(reg >= 0x4000) { - color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; } - break; + else + { + color = options.PpuRegisterReadColor; + } + } + else if (reg <= 0x217F) + { + color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; + } + else if (reg <= 0x2183) + { + color = isWrite ? options.WorkRamRegisterWriteColor : options.WorkRamRegisterReadColor; + } + else if (reg >= 0x4000) + { + color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; + } + break; } - if(drawBackground){ + if (drawBackground) + { color = 0xFF000000 | ((color >> 1) & 0x7F7F7F); - } else { + } + else + { color |= 0xFF000000; } @@ -224,10 +301,13 @@ void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t uint32_t y = std::min(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; @@ -247,14 +327,17 @@ 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; @@ -264,25 +347,29 @@ 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]); } } @@ -290,20 +377,24 @@ 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); } } diff --git a/Core/EventManager.h b/Core/EventManager.h index 421650d..bc405bd 100644 --- a/Core/EventManager.h +++ b/Core/EventManager.h @@ -19,15 +19,15 @@ 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 _debugEvents; vector _prevDebugEvents; vector _sentEvents; - + vector _snapshot; int16_t _snapshotScanline = -1; uint16_t _snapshotCycle = 0; @@ -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); }; diff --git a/Core/EventType.h b/Core/EventType.h index 153b2c4..b161169 100644 --- a/Core/EventType.h +++ b/Core/EventType.h @@ -14,4 +14,4 @@ enum class EventType GbStartFrame, GbEndFrame, EventTypeSize -}; \ No newline at end of file +}; diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index 5020d21..c8ba031 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -11,24 +11,38 @@ #include "DebugUtilities.h" #include "../Utilities/HexUtilities.h" -const vector ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } }; -const vector ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } }; -const vector ExpressionEvaluator::_unaryOperators = { { "+", "-", "~", "!" } }; -const vector ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } }; -const std::unordered_set ExpressionEvaluator::_operators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||", "~", "!", "(", ")", "{", "}", "[", "]" } }; +const vector ExpressionEvaluator::_binaryOperators = { + {"*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||"} +}; +const vector ExpressionEvaluator::_binaryPrecedence = {{10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1}}; +const vector ExpressionEvaluator::_unaryOperators = {{"+", "-", "~", "!"}}; +const vector ExpressionEvaluator::_unaryPrecedence = {{11, 11, 11, 11}}; +const std::unordered_set ExpressionEvaluator::_operators = { + { + "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||", "~", "!", "(", + ")", "{", "}", "[", "]" + } +}; -bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator) +bool ExpressionEvaluator::IsOperator(string token, int& precedence, bool unaryOperator) { - if(unaryOperator) { - for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) { - if(token.compare(_unaryOperators[i]) == 0) { + if (unaryOperator) + { + for (size_t i = 0, len = _unaryOperators.size(); i < len; i++) + { + if (token.compare(_unaryOperators[i]) == 0) + { precedence = _unaryPrecedence[i]; return true; } } - } else { - for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) { - if(token.compare(_binaryOperators[i]) == 0) { + } + else + { + for (size_t i = 0, len = _binaryOperators.size(); i < len; i++) + { + if (token.compare(_binaryOperators[i]) == 0) + { precedence = _binaryPrecedence[i]; return true; } @@ -39,15 +53,22 @@ bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOp EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator) { - if(unaryOperator) { - for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) { - if(token.compare(_unaryOperators[i]) == 0) { + if (unaryOperator) + { + for (size_t i = 0, len = _unaryOperators.size(); i < len; i++) + { + if (token.compare(_unaryOperators[i]) == 0) + { return (EvalOperators)(EvalOperators::Plus + i); } } - } else { - for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) { - if(token.compare(_binaryOperators[i]) == 0) { + } + else + { + for (size_t i = 0, len = _binaryOperators.size(); i < len; i++) + { + if (token.compare(_binaryOperators[i]) == 0) + { return (EvalOperators)(EvalOperators::Multiplication + i); } } @@ -55,130 +76,209 @@ EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator) return EvalOperators::Addition; } -bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data) +bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t& pos, string& output, ExpressionData& data) { string token; size_t initialPos = pos; size_t len = expression.size(); - do { + do + { char c = std::tolower(expression[pos]); - if((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '@') { + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '@') + { //Only letters, numbers and underscore are allowed in code labels token += c; pos++; - } else { + } + else + { break; } - } while(pos < len); + } + while (pos < len); int64_t tokenValue = -1; - if(_cpuType == CpuType::Gsu) { + if (_cpuType == CpuType::Gsu) + { tokenValue = ProcessGsuTokens(token); - } else if(_cpuType == CpuType::Gameboy) { + } + else if (_cpuType == CpuType::Gameboy) + { tokenValue = ProcessGameboyTokens(token); - } else if(_cpuType == CpuType::Spc) { + } + else if (_cpuType == CpuType::Spc) + { tokenValue = ProcessCpuSpcTokens(token, true); - } else { // Cpu or Sa1 + } + else + { + // Cpu or Sa1 tokenValue = ProcessCpuSpcTokens(token, false); } - if(tokenValue != -1) { + if (tokenValue != -1) + { output += std::to_string(tokenValue); return true; } int64_t sharedToken = ProcessSharedTokens(token); - if(sharedToken != -1) { + if (sharedToken != -1) + { output += std::to_string(sharedToken); return true; } string originalExpression = expression.substr(initialPos, pos - initialPos); bool validLabel = _labelManager->ContainsLabel(originalExpression); - if(!validLabel) { + if (!validLabel) + { //Check if a multi-byte label exists for this name string label = originalExpression + "+0"; validLabel = _labelManager->ContainsLabel(label); } - if(validLabel) { + if (validLabel) + { data.Labels.push_back(originalExpression); output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1); return true; - } else { + } + else + { return false; } } int64_t ExpressionEvaluator::ProcessCpuSpcTokens(string token, bool spc700) { - if(token == "a") { + if (token == "a") + { return EvalValues::RegA; - } else if(token == "x") { + } + else if (token == "x") + { return EvalValues::RegX; - } else if(token == "y") { + } + else if (token == "y") + { return EvalValues::RegY; - } else if(token == "ps") { + } + else if (token == "ps") + { return EvalValues::RegPS; - } else if (token == "pscarry") { + } + else if (token == "pscarry") + { return EvalValues::RegPS_Carry; - } else if (token == "pszero") { + } + else if (token == "pszero") + { return EvalValues::RegPS_Zero; - } else if (token == "psinterrupt") { + } + else if (token == "psinterrupt") + { return EvalValues::RegPS_Interrupt; - } else if (token == "psdecimal") { + } + else if (token == "psdecimal") + { return EvalValues::RegPS_Decimal; - } else if (token == "psoverflow") { + } + else if (token == "psoverflow") + { return EvalValues::RegPS_Overflow; - } else if (token == "psnegative") { + } + else if (token == "psnegative") + { return EvalValues::RegPS_Negative; - } else if (token == "ps8bit" && !spc700) { + } + else if (token == "ps8bit" && !spc700) + { return EvalValues::RegPS_8bit; - } else if (token == "ps8bitindex" && !spc700) { + } + else if (token == "ps8bitindex" && !spc700) + { return EvalValues::RegPS_8bitIndex; - } else if (token == "ps16bit" && !spc700) { + } + else if (token == "ps16bit" && !spc700) + { return EvalValues::RegPS_16bit; - } else if (token == "ps16bitindex" && !spc700) { + } + else if (token == "ps16bitindex" && !spc700) + { return EvalValues::RegPS_16bitIndex; - } else if (token == "pshalfcarry" && spc700) { + } + else if (token == "pshalfcarry" && spc700) + { return EvalValues::RegPS_HalfCarry; - } else if (token == "psbreak" && spc700) { + } + else if (token == "psbreak" && spc700) + { return EvalValues::RegPS_Break; - } else if (token == "psstackzp" && spc700) { + } + else if (token == "psstackzp" && spc700) + { return EvalValues::RegPS_StackZeropage; - } else if(token == "sp") { + } + else if (token == "sp") + { return EvalValues::RegSP; - } else if(token == "pc") { + } + else if (token == "pc") + { return EvalValues::RegPC; - } else if(token == "oppc") { + } + else if (token == "oppc") + { return EvalValues::RegOpPC; - } else if(token == "previousoppc") { + } + else if (token == "previousoppc") + { return EvalValues::PreviousOpPC; - } else if(token == "irq") { + } + else if (token == "irq") + { return EvalValues::Irq; - } else if(token == "nmi") { + } + else if (token == "nmi") + { return EvalValues::Nmi; } return -1; } -int64_t ExpressionEvaluator::ProcessSharedTokens(string token) +int64_t ExpressionEvaluator::ProcessSharedTokens(string token) { - if(token == "frame") { + if (token == "frame") + { return EvalValues::PpuFrameCount; - } else if(token == "cycle") { + } + else if (token == "cycle") + { return EvalValues::PpuCycle; - } else if(token == "scanline") { + } + else if (token == "scanline") + { return EvalValues::PpuScanline; - } else if(token == "value") { + } + else if (token == "value") + { return EvalValues::Value; - } else if(token == "address") { + } + else if (token == "address") + { return EvalValues::Address; - } else if(token == "romaddress") { + } + else if (token == "romaddress") + { return EvalValues::AbsoluteAddress; - } else if(token == "iswrite") { + } + else if (token == "iswrite") + { return EvalValues::IsWrite; - } else if(token == "isread") { + } + else if (token == "isread") + { return EvalValues::IsRead; } return -1; @@ -186,49 +286,92 @@ int64_t ExpressionEvaluator::ProcessSharedTokens(string token) int64_t ExpressionEvaluator::ProcessGsuTokens(string token) { - if(token == "r0") { + if (token == "r0") + { return EvalValues::R0; - } else if(token == "r1") { + } + else if (token == "r1") + { return EvalValues::R1; - } else if(token == "r2") { + } + else if (token == "r2") + { return EvalValues::R2; - } else if(token == "r3") { + } + else if (token == "r3") + { return EvalValues::R3; - } else if(token == "r4") { + } + else if (token == "r4") + { return EvalValues::R4; - } else if(token == "r5") { + } + else if (token == "r5") + { return EvalValues::R5; - } else if(token == "r6") { + } + else if (token == "r6") + { return EvalValues::R6; - } else if(token == "r7") { + } + else if (token == "r7") + { return EvalValues::R7; - } else if(token == "r8") { + } + else if (token == "r8") + { return EvalValues::R8; - } else if(token == "r9") { + } + else if (token == "r9") + { return EvalValues::R9; - } else if(token == "r10") { + } + else if (token == "r10") + { return EvalValues::R10; - } else if(token == "r11") { + } + else if (token == "r11") + { return EvalValues::R11; - } else if(token == "r12") { + } + else if (token == "r12") + { return EvalValues::R12; - } else if(token == "r13") { + } + else if (token == "r13") + { return EvalValues::R13; - } else if(token == "r14") { + } + else if (token == "r14") + { return EvalValues::R14; - } else if(token == "r15") { + } + else if (token == "r15") + { return EvalValues::R15; - } else if(token == "srcreg") { + } + else if (token == "srcreg") + { return EvalValues::SrcReg; - } else if(token == "dstreg") { + } + else if (token == "dstreg") + { return EvalValues::DstReg; - } else if(token == "sfr") { + } + else if (token == "sfr") + { return EvalValues::SFR; - } else if(token == "pbr") { + } + else if (token == "pbr") + { return EvalValues::PBR; - } else if(token == "rombr") { + } + else if (token == "rombr") + { return EvalValues::RomBR; - } else if(token == "rambr") { + } + else if (token == "rambr") + { return EvalValues::RamBR; } return -1; @@ -237,129 +380,190 @@ int64_t ExpressionEvaluator::ProcessGsuTokens(string token) int64_t ExpressionEvaluator::ProcessGameboyTokens(string token) { - if(token == "a") { + if (token == "a") + { return EvalValues::RegA; - } else if(token == "b") { + } + else if (token == "b") + { return EvalValues::RegB; - } else if(token == "c") { + } + else if (token == "c") + { return EvalValues::RegC; - } else if(token == "d") { + } + else if (token == "d") + { return EvalValues::RegD; - } else if(token == "e") { + } + else if (token == "e") + { return EvalValues::RegE; - } else if(token == "f") { + } + else if (token == "f") + { return EvalValues::RegF; - } else if(token == "h") { + } + else if (token == "h") + { return EvalValues::RegH; - } else if(token == "l") { + } + else if (token == "l") + { return EvalValues::RegL; - } else if(token == "af") { + } + else if (token == "af") + { return EvalValues::RegAF; - } else if(token == "bc") { + } + else if (token == "bc") + { return EvalValues::RegBC; - } else if(token == "de") { + } + else if (token == "de") + { return EvalValues::RegDE; - } else if(token == "hl") { + } + else if (token == "hl") + { return EvalValues::RegHL; - } else if(token == "sp") { + } + else if (token == "sp") + { return EvalValues::RegSP; - } else if(token == "pc") { + } + else if (token == "pc") + { return EvalValues::RegPC; } return -1; } -string ExpressionEvaluator::GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp) +string ExpressionEvaluator::GetNextToken(string expression, size_t& pos, ExpressionData& data, bool& success, + bool previousTokenIsOp) { string output; success = true; char c = std::tolower(expression[pos]); - if(c == '$') { + if (c == '$') + { //Hex numbers pos++; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) + { output += c; - } else { + } + else + { break; } } - if(output.empty()) { + if (output.empty()) + { //No numbers followed the hex mark, this isn't a valid expression success = false; } output = std::to_string((uint32_t)HexUtilities::FromHex(output)); - } else if(c == '%' && previousTokenIsOp) { + } + else if (c == '%' && previousTokenIsOp) + { //Binary numbers pos++; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if(c == '0' || c == '1') { + if (c == '0' || c == '1') + { output += c; - } else { + } + else + { break; } } - if(output.empty()) { + if (output.empty()) + { //No numbers followed the binary mark, this isn't a valid expression success = false; } uint32_t value = 0; - for(size_t i = 0; i < output.size(); i++) { + for (size_t i = 0; i < output.size(); i++) + { value <<= 1; value |= output[i] == '1' ? 1 : 0; } output = std::to_string(value); - } else if(c >= '0' && c <= '9') { + } + else if (c >= '0' && c <= '9') + { //Regular numbers - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if(c >= '0' && c <= '9') { + if (c >= '0' && c <= '9') + { output += c; - } else { + } + else + { break; } } - } else if((c < 'a' || c > 'z') && c != '_' && c != '@') { + } + else if ((c < 'a' || c > 'z') && c != '_' && c != '@') + { //Operators string operatorToken; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); operatorToken += c; - if(output.empty() || _operators.find(operatorToken) != _operators.end()) { + if (output.empty() || _operators.find(operatorToken) != _operators.end()) + { //If appending the next char results in a valid operator, append it (or if this is the first character) output += c; - } else { + } + else + { //Reached the end of the operator, return break; } } - } else { + } + else + { //Special tokens and labels success = CheckSpecialTokens(expression, pos, output, data); } return output; } - -bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue) + +bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack& opStack, + std::stack& precedenceStack, vector& outputQueue) { - if(opStack.empty()) { + if (opStack.empty()) + { return false; } - while(opStack.top() != evalOp) { + while (opStack.top() != evalOp) + { outputQueue.push_back(opStack.top()); opStack.pop(); precedenceStack.pop(); - if(opStack.empty()) { + if (opStack.empty()) + { return false; } } - if(evalOp != EvalOperators::Parenthesis) { + if (evalOp != EvalOperators::Parenthesis) + { outputQueue.push_back(opStack.top()); } opStack.pop(); @@ -368,9 +572,9 @@ bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stac return true; } -bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) +bool ExpressionEvaluator::ToRpn(string expression, ExpressionData& data) { - std::stack opStack = std::stack(); + std::stack opStack = std::stack(); std::stack precedenceStack; size_t position = 0; @@ -381,30 +585,36 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) bool previousTokenIsOp = true; bool operatorExpected = false; bool operatorOrEndTokenExpected = false; - while(true) { + while (true) + { bool success = true; string token = GetNextToken(expression, position, data, success, previousTokenIsOp); - if(!success) { + if (!success) + { return false; } - if(token.empty()) { + if (token.empty()) + { break; } bool requireOperator = operatorExpected; bool requireOperatorOrEndToken = operatorOrEndTokenExpected; bool unaryOperator = previousTokenIsOp; - + operatorExpected = false; operatorOrEndTokenExpected = false; previousTokenIsOp = false; - + int precedence = 0; - if(IsOperator(token, precedence, unaryOperator)) { + if (IsOperator(token, precedence, unaryOperator)) + { EvalOperators op = GetOperator(token, unaryOperator); bool rightAssociative = unaryOperator; - while(!opStack.empty() && ((rightAssociative && precedence < precedenceStack.top()) || (!rightAssociative && precedence <= precedenceStack.top()))) { + while (!opStack.empty() && ((rightAssociative && precedence < precedenceStack.top()) || (!rightAssociative && + precedence <= precedenceStack.top()))) + { //Pop operators from the stack until we find something with higher priority (or empty the stack) data.RpnQueue.push_back(opStack.top()); opStack.pop(); @@ -414,59 +624,85 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) precedenceStack.push(precedence); previousTokenIsOp = true; - } else if(requireOperator) { + } + else if (requireOperator) + { //We needed an operator, and got something else, this isn't a valid expression (e.g "(3)4" or "[$00]22") return false; - } else if(requireOperatorOrEndToken && token[0] != ')' && token[0] != ']' && token[0] != '}') { + } + else if (requireOperatorOrEndToken && token[0] != ')' && token[0] != ']' && token[0] != '}') + { //We needed an operator or close token - this isn't a valid expression (e.g "%1134") return false; - } else if(token[0] == '(') { + } + else if (token[0] == '(') + { parenthesisCount++; opStack.push(EvalOperators::Parenthesis); precedenceStack.push(0); previousTokenIsOp = true; - } else if(token[0] == ')') { + } + else if (token[0] == ')') + { parenthesisCount--; - if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) { + if (!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else if(token[0] == '[') { + } + else if (token[0] == '[') + { bracketCount++; opStack.push(EvalOperators::Bracket); precedenceStack.push(0); - } else if(token[0] == ']') { + } + else if (token[0] == ']') + { bracketCount--; - if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) { + if (!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else if(token[0] == '{') { + } + else if (token[0] == '{') + { braceCount++; opStack.push(EvalOperators::Braces); precedenceStack.push(0); - } else if(token[0] == '}') { + } + else if (token[0] == '}') + { braceCount--; - if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)){ + if (!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else { - if(token[0] < '0' || token[0] > '9') { + } + else + { + if (token[0] < '0' || token[0] > '9') + { return false; - } else { + } + else + { data.RpnQueue.push_back(std::stoll(token)); operatorOrEndTokenExpected = true; } } } - if(braceCount || bracketCount || parenthesisCount) { + if (braceCount || bracketCount || parenthesisCount) + { //Mismatching number of brackets/braces/parenthesis return false; } - while(!opStack.empty()) { + while (!opStack.empty()) + { data.RpnQueue.push_back(opStack.top()); opStack.pop(); } @@ -474,9 +710,11 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) return true; } -int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo) +int32_t ExpressionEvaluator::Evaluate(ExpressionData& data, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo) { - if(data.RpnQueue.empty()) { + if (data.RpnQueue.empty()) + { resultType = EvalResultType::Invalid; return 0; } @@ -486,188 +724,325 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E int64_t left = 0; resultType = EvalResultType::Numeric; - for(size_t i = 0, len = data.RpnQueue.size(); i < len; i++) { + for (size_t i = 0, len = data.RpnQueue.size(); i < len; i++) + { int64_t token = data.RpnQueue[i]; - if(token >= EvalValues::RegA) { + if (token >= EvalValues::RegA) + { //Replace value with a special value - if(token >= EvalValues::FirstLabelIndex) { + if (token >= EvalValues::FirstLabelIndex) + { int64_t labelIndex = token - EvalValues::FirstLabelIndex; - if((size_t)labelIndex < data.Labels.size()) { + if ((size_t)labelIndex < data.Labels.size()) + { token = _labelManager->GetLabelRelativeAddress(data.Labels[(uint32_t)labelIndex], _cpuType); - if(token < -1) { + if (token < -1) + { //Label doesn't exist, try to find a matching multi-byte label string label = data.Labels[(uint32_t)labelIndex] + "+0"; token = _labelManager->GetLabelRelativeAddress(label, _cpuType); } - } else { + } + else + { token = -2; } - if(token < 0) { + if (token < 0) + { //Label is no longer valid resultType = token == -1 ? EvalResultType::OutOfScope : EvalResultType::Invalid; return 0; } - } else { - switch(token) { + } + else + { + switch (token) + { /*case EvalValues::RegOpPC: token = state.Cpu.DebugPC; break;*/ - case EvalValues::PpuFrameCount: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.FrameCount : state.Ppu.FrameCount; break; - case EvalValues::PpuCycle: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Cycle : state.Ppu.Cycle; break; - case EvalValues::PpuScanline: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Scanline : state.Ppu.Scanline; break; - case EvalValues::Value: token = operationInfo.Value; break; - case EvalValues::Address: token = operationInfo.Address; break; + case EvalValues::PpuFrameCount: token = _cpuType == CpuType::Gameboy + ? state.Gameboy.Ppu.FrameCount + : state.Ppu.FrameCount; + break; + case EvalValues::PpuCycle: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Cycle : state.Ppu.Cycle; + break; + case EvalValues::PpuScanline: token = _cpuType == CpuType::Gameboy + ? state.Gameboy.Ppu.Scanline + : state.Ppu.Scanline; + break; + case EvalValues::Value: token = operationInfo.Value; + break; + case EvalValues::Address: token = operationInfo.Address; + break; //case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(operationInfo.Address); break; - case EvalValues::IsWrite: token = operationInfo.Type == MemoryOperationType::Write || operationInfo.Type == MemoryOperationType::DmaWrite; break; - case EvalValues::IsRead: token = operationInfo.Type != MemoryOperationType::Write && operationInfo.Type != MemoryOperationType::DmaWrite; break; + case EvalValues::IsWrite: token = operationInfo.Type == MemoryOperationType::Write || operationInfo.Type == + MemoryOperationType::DmaWrite; + break; + case EvalValues::IsRead: token = operationInfo.Type != MemoryOperationType::Write && operationInfo.Type != + MemoryOperationType::DmaWrite; + break; //case EvalValues::PreviousOpPC: token = state.CPU.PreviousDebugPC; break; - default: - switch(_cpuType) { - case CpuType::Cpu: - case CpuType::Sa1: - switch(token) { - case EvalValues::RegA: token = state.Cpu.A; break; - case EvalValues::RegX: token = state.Cpu.X; break; - case EvalValues::RegY: token = state.Cpu.Y; break; - case EvalValues::RegSP: token = state.Cpu.SP; break; - case EvalValues::RegPS: token = state.Cpu.PS; break; - case EvalValues::RegPC: token = state.Cpu.PC; break; - case EvalValues::Nmi: token = state.Cpu.NmiFlag; resultType = EvalResultType::Boolean; break; - case EvalValues::Irq: token = state.Cpu.IrqSource != 0; resultType = EvalResultType::Boolean; break; - case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; break; - case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; break; - case EvalValues::RegPS_Interrupt: token = (state.Cpu.PS & 4) != 0; break; - case EvalValues::RegPS_Decimal: token = (state.Cpu.PS & 8) != 0; break; - case EvalValues::RegPS_8bitIndex: token = (state.Cpu.PS & 16) != 0; break; - case EvalValues::RegPS_8bit: token = (state.Cpu.PS & 32) != 0; break; - case EvalValues::RegPS_16bitIndex: token = (state.Cpu.PS & 16) == 0; break; - case EvalValues::RegPS_16bit: token = (state.Cpu.PS & 32) == 0; break; - case EvalValues::RegPS_Overflow: token = (state.Cpu.PS & 64) != 0; break; - case EvalValues::RegPS_Negative: token = (state.Cpu.PS & 128) != 0; break; - } - break; - - case CpuType::Spc: - switch(token) { - case EvalValues::RegA: token = state.Spc.A; break; - case EvalValues::RegX: token = state.Spc.X; break; - case EvalValues::RegY: token = state.Spc.Y; break; - case EvalValues::RegSP: token = state.Spc.SP; break; - case EvalValues::RegPS: token = state.Spc.PS; break; - case EvalValues::RegPC: token = state.Spc.PC; break; - case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; break; - case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; break; - case EvalValues::RegPS_Interrupt: (state.Cpu.PS & 4) != 0; break; - case EvalValues::RegPS_HalfCarry: (state.Cpu.PS & 8) != 0; break; - case EvalValues::RegPS_Break: (state.Cpu.PS & 16) != 0; break; - case EvalValues::RegPS_StackZeropage: (state.Cpu.PS & 32) != 0; break; - case EvalValues::RegPS_Overflow: (state.Cpu.PS & 64) != 0; break; - case EvalValues::RegPS_Negative: (state.Cpu.PS & 128) != 0; break; - } - break; - - case CpuType::Gameboy: - switch(token) { - case EvalValues::RegA: token = state.Gameboy.Cpu.A; break; - case EvalValues::RegB: token = state.Gameboy.Cpu.B; break; - case EvalValues::RegC: token = state.Gameboy.Cpu.C; break; - case EvalValues::RegD: token = state.Gameboy.Cpu.D; break; - case EvalValues::RegE: token = state.Gameboy.Cpu.E; break; - case EvalValues::RegF: token = state.Gameboy.Cpu.Flags; break; - case EvalValues::RegH: token = state.Gameboy.Cpu.H; break; - case EvalValues::RegL: token = state.Gameboy.Cpu.L; break; - case EvalValues::RegAF: token = (state.Gameboy.Cpu.A << 8) | state.Gameboy.Cpu.Flags; break; - case EvalValues::RegBC: token = (state.Gameboy.Cpu.B << 8) | state.Gameboy.Cpu.C; break; - case EvalValues::RegDE: token = (state.Gameboy.Cpu.D << 8) | state.Gameboy.Cpu.E; break; - case EvalValues::RegHL: token = (state.Gameboy.Cpu.H << 8) | state.Gameboy.Cpu.L; break; - case EvalValues::RegSP: token = state.Gameboy.Cpu.SP; break; - case EvalValues::RegPC: token = state.Gameboy.Cpu.PC; break; - } - break; - - case CpuType::Gsu: - switch(token) { - case EvalValues::R0: token = state.Gsu.R[0]; break; - case EvalValues::R1: token = state.Gsu.R[1]; break; - case EvalValues::R2: token = state.Gsu.R[2]; break; - case EvalValues::R3: token = state.Gsu.R[3]; break; - case EvalValues::R4: token = state.Gsu.R[4]; break; - case EvalValues::R5: token = state.Gsu.R[5]; break; - case EvalValues::R6: token = state.Gsu.R[6]; break; - case EvalValues::R7: token = state.Gsu.R[7]; break; - case EvalValues::R8: token = state.Gsu.R[8]; break; - case EvalValues::R9: token = state.Gsu.R[9]; break; - case EvalValues::R10: token = state.Gsu.R[10]; break; - case EvalValues::R11: token = state.Gsu.R[11]; break; - case EvalValues::R12: token = state.Gsu.R[12]; break; - case EvalValues::R13: token = state.Gsu.R[13]; break; - case EvalValues::R14: token = state.Gsu.R[14]; break; - case EvalValues::R15: token = state.Gsu.R[15]; break; - - case EvalValues::SrcReg: token = state.Gsu.SrcReg; break; - case EvalValues::DstReg: token = state.Gsu.DestReg; break; - - case EvalValues::SFR: token = (state.Gsu.SFR.GetFlagsHigh() << 8) | state.Gsu.SFR.GetFlagsLow(); break; - case EvalValues::PBR: token = state.Gsu.ProgramBank; break; - case EvalValues::RomBR: token = state.Gsu.RomBank; break; - case EvalValues::RamBR: token = state.Gsu.RamBank; break; - } - break; - - case CpuType::NecDsp: - case CpuType::Cx4: - throw std::runtime_error("Invalid CPU type"); + default: + switch (_cpuType) + { + case CpuType::Cpu: + case CpuType::Sa1: + switch (token) + { + case EvalValues::RegA: token = state.Cpu.A; + break; + case EvalValues::RegX: token = state.Cpu.X; + break; + case EvalValues::RegY: token = state.Cpu.Y; + break; + case EvalValues::RegSP: token = state.Cpu.SP; + break; + case EvalValues::RegPS: token = state.Cpu.PS; + break; + case EvalValues::RegPC: token = state.Cpu.PC; + break; + case EvalValues::Nmi: token = state.Cpu.NmiFlag; + resultType = EvalResultType::Boolean; + break; + case EvalValues::Irq: token = state.Cpu.IrqSource != 0; + resultType = EvalResultType::Boolean; + break; + case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; + break; + case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; + break; + case EvalValues::RegPS_Interrupt: token = (state.Cpu.PS & 4) != 0; + break; + case EvalValues::RegPS_Decimal: token = (state.Cpu.PS & 8) != 0; + break; + case EvalValues::RegPS_8bitIndex: token = (state.Cpu.PS & 16) != 0; + break; + case EvalValues::RegPS_8bit: token = (state.Cpu.PS & 32) != 0; + break; + case EvalValues::RegPS_16bitIndex: token = (state.Cpu.PS & 16) == 0; + break; + case EvalValues::RegPS_16bit: token = (state.Cpu.PS & 32) == 0; + break; + case EvalValues::RegPS_Overflow: token = (state.Cpu.PS & 64) != 0; + break; + case EvalValues::RegPS_Negative: token = (state.Cpu.PS & 128) != 0; + break; } break; + + case CpuType::Spc: + switch (token) + { + case EvalValues::RegA: token = state.Spc.A; + break; + case EvalValues::RegX: token = state.Spc.X; + break; + case EvalValues::RegY: token = state.Spc.Y; + break; + case EvalValues::RegSP: token = state.Spc.SP; + break; + case EvalValues::RegPS: token = state.Spc.PS; + break; + case EvalValues::RegPC: token = state.Spc.PC; + break; + case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; + break; + case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; + break; + case EvalValues::RegPS_Interrupt: (state.Cpu.PS & 4) != 0; + break; + case EvalValues::RegPS_HalfCarry: (state.Cpu.PS & 8) != 0; + break; + case EvalValues::RegPS_Break: (state.Cpu.PS & 16) != 0; + break; + case EvalValues::RegPS_StackZeropage: (state.Cpu.PS & 32) != 0; + break; + case EvalValues::RegPS_Overflow: (state.Cpu.PS & 64) != 0; + break; + case EvalValues::RegPS_Negative: (state.Cpu.PS & 128) != 0; + break; + } + break; + + case CpuType::Gameboy: + switch (token) + { + case EvalValues::RegA: token = state.Gameboy.Cpu.A; + break; + case EvalValues::RegB: token = state.Gameboy.Cpu.B; + break; + case EvalValues::RegC: token = state.Gameboy.Cpu.C; + break; + case EvalValues::RegD: token = state.Gameboy.Cpu.D; + break; + case EvalValues::RegE: token = state.Gameboy.Cpu.E; + break; + case EvalValues::RegF: token = state.Gameboy.Cpu.Flags; + break; + case EvalValues::RegH: token = state.Gameboy.Cpu.H; + break; + case EvalValues::RegL: token = state.Gameboy.Cpu.L; + break; + case EvalValues::RegAF: token = (state.Gameboy.Cpu.A << 8) | state.Gameboy.Cpu.Flags; + break; + case EvalValues::RegBC: token = (state.Gameboy.Cpu.B << 8) | state.Gameboy.Cpu.C; + break; + case EvalValues::RegDE: token = (state.Gameboy.Cpu.D << 8) | state.Gameboy.Cpu.E; + break; + case EvalValues::RegHL: token = (state.Gameboy.Cpu.H << 8) | state.Gameboy.Cpu.L; + break; + case EvalValues::RegSP: token = state.Gameboy.Cpu.SP; + break; + case EvalValues::RegPC: token = state.Gameboy.Cpu.PC; + break; + } + break; + + case CpuType::Gsu: + switch (token) + { + case EvalValues::R0: token = state.Gsu.R[0]; + break; + case EvalValues::R1: token = state.Gsu.R[1]; + break; + case EvalValues::R2: token = state.Gsu.R[2]; + break; + case EvalValues::R3: token = state.Gsu.R[3]; + break; + case EvalValues::R4: token = state.Gsu.R[4]; + break; + case EvalValues::R5: token = state.Gsu.R[5]; + break; + case EvalValues::R6: token = state.Gsu.R[6]; + break; + case EvalValues::R7: token = state.Gsu.R[7]; + break; + case EvalValues::R8: token = state.Gsu.R[8]; + break; + case EvalValues::R9: token = state.Gsu.R[9]; + break; + case EvalValues::R10: token = state.Gsu.R[10]; + break; + case EvalValues::R11: token = state.Gsu.R[11]; + break; + case EvalValues::R12: token = state.Gsu.R[12]; + break; + case EvalValues::R13: token = state.Gsu.R[13]; + break; + case EvalValues::R14: token = state.Gsu.R[14]; + break; + case EvalValues::R15: token = state.Gsu.R[15]; + break; + + case EvalValues::SrcReg: token = state.Gsu.SrcReg; + break; + case EvalValues::DstReg: token = state.Gsu.DestReg; + break; + + case EvalValues::SFR: token = (state.Gsu.SFR.GetFlagsHigh() << 8) | state.Gsu.SFR.GetFlagsLow(); + break; + case EvalValues::PBR: token = state.Gsu.ProgramBank; + break; + case EvalValues::RomBR: token = state.Gsu.RomBank; + break; + case EvalValues::RamBR: token = state.Gsu.RamBank; + break; + } + break; + + case CpuType::NecDsp: + case CpuType::Cx4: + throw std::runtime_error("Invalid CPU type"); + } + break; } } - } else if(token >= EvalOperators::Multiplication) { + } + else if (token >= EvalOperators::Multiplication) + { right = operandStack[--pos]; - if(pos > 0 && token <= EvalOperators::LogicalOr) { + if (pos > 0 && token <= EvalOperators::LogicalOr) + { //Only do this for binary operators left = operandStack[--pos]; } resultType = EvalResultType::Numeric; - switch(token) { - case EvalOperators::Multiplication: token = left * right; break; - case EvalOperators::Division: - if(right == 0) { - resultType = EvalResultType::DivideBy0; - return 0; - } - token = left / right; break; - case EvalOperators::Modulo: - if(right == 0) { - resultType = EvalResultType::DivideBy0; - return 0; - } - token = left % right; - break; - case EvalOperators::Addition: token = left + right; break; - case EvalOperators::Substration: token = left - right; break; - case EvalOperators::ShiftLeft: token = left << right; break; - case EvalOperators::ShiftRight: token = left >> right; break; - case EvalOperators::SmallerThan: token = left < right; resultType = EvalResultType::Boolean; break; - case EvalOperators::SmallerOrEqual: token = left <= right; resultType = EvalResultType::Boolean; break; - case EvalOperators::GreaterThan: token = left > right; resultType = EvalResultType::Boolean; break; - case EvalOperators::GreaterOrEqual: token = left >= right; resultType = EvalResultType::Boolean; break; - case EvalOperators::Equal: token = left == right; resultType = EvalResultType::Boolean; break; - case EvalOperators::NotEqual: token = left != right; resultType = EvalResultType::Boolean; break; - case EvalOperators::BinaryAnd: token = left & right; break; - case EvalOperators::BinaryXor: token = left ^ right; break; - case EvalOperators::BinaryOr: token = left | right; break; - case EvalOperators::LogicalAnd: token = left && right; resultType = EvalResultType::Boolean; break; - case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break; + switch (token) + { + case EvalOperators::Multiplication: token = left * right; + break; + case EvalOperators::Division: + if (right == 0) + { + resultType = EvalResultType::DivideBy0; + return 0; + } + token = left / right; + break; + case EvalOperators::Modulo: + if (right == 0) + { + resultType = EvalResultType::DivideBy0; + return 0; + } + token = left % right; + break; + case EvalOperators::Addition: token = left + right; + break; + case EvalOperators::Substration: token = left - right; + break; + case EvalOperators::ShiftLeft: token = left << right; + break; + case EvalOperators::ShiftRight: token = left >> right; + break; + case EvalOperators::SmallerThan: token = left < right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::SmallerOrEqual: token = left <= right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::GreaterThan: token = left > right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::GreaterOrEqual: token = left >= right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::Equal: token = left == right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::NotEqual: token = left != right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::BinaryAnd: token = left & right; + break; + case EvalOperators::BinaryXor: token = left ^ right; + break; + case EvalOperators::BinaryOr: token = left | right; + break; + case EvalOperators::LogicalAnd: token = left && right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::LogicalOr: token = left || right; + resultType = EvalResultType::Boolean; + break; //Unary operators - case EvalOperators::Plus: token = right; break; - case EvalOperators::Minus: token = -right; break; - case EvalOperators::BinaryNot: token = ~right; break; - case EvalOperators::LogicalNot: token = !right; break; - case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(_cpuMemory, (uint32_t)right); break; - case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(_cpuMemory, (uint32_t)right); break; - default: throw std::runtime_error("Invalid operator"); + case EvalOperators::Plus: token = right; + break; + case EvalOperators::Minus: token = -right; + break; + case EvalOperators::BinaryNot: token = ~right; + break; + case EvalOperators::LogicalNot: token = !right; + break; + case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(_cpuMemory, (uint32_t)right); + break; + case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord( + _cpuMemory, (uint32_t)right); + break; + default: throw std::runtime_error("Invalid operator"); } } operandStack[pos++] = token; @@ -683,67 +1058,82 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger, CpuType cpuType) _cpuMemory = DebugUtilities::GetCpuMemoryType(cpuType); } -ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool &success) +ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool& success) { ExpressionData* cachedData = PrivateGetRpnList(expression, success); - if(cachedData) { + if (cachedData) + { return *cachedData; - } else { + } + else + { return ExpressionData(); } } ExpressionData* ExpressionEvaluator::PrivateGetRpnList(string expression, bool& success) { - ExpressionData *cachedData = nullptr; + ExpressionData* cachedData = nullptr; { LockHandler lock = _cacheLock.AcquireSafe(); auto result = _cache.find(expression); - if(result != _cache.end()) { + if (result != _cache.end()) + { cachedData = &(result->second); } } - if(cachedData == nullptr) { + if (cachedData == nullptr) + { string fixedExp = expression; fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end()); ExpressionData data; success = ToRpn(fixedExp, data); - if(success) { + if (success) + { LockHandler lock = _cacheLock.AcquireSafe(); _cache[expression] = data; cachedData = &_cache[expression]; } - } else { + } + else + { success = true; } return cachedData; } -int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo, bool& success) +int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo, bool& success) { success = true; - ExpressionData *cachedData = PrivateGetRpnList(expression, success); + ExpressionData* cachedData = PrivateGetRpnList(expression, success); - if(!success) { + if (!success) + { resultType = EvalResultType::Invalid; return 0; } - return Evaluate(*cachedData, state, resultType, operationInfo); + return Evaluate(*cachedData, state, resultType, operationInfo); } -int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo) +int32_t ExpressionEvaluator::Evaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo) { - try { + try + { bool success; int32_t result = PrivateEvaluate(expression, state, resultType, operationInfo, success); - if(success) { + if (success) + { return result; } - } catch(std::exception&) { + } + catch (std::exception&) + { } resultType = EvalResultType::Invalid; return 0; @@ -751,33 +1141,38 @@ int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, Eval bool ExpressionEvaluator::Validate(string expression) { - try { + try + { DebugState state; EvalResultType type; MemoryOperationInfo operationInfo; bool success; PrivateEvaluate(expression, state, type, operationInfo, success); return success; - } catch(std::exception&) { + } + catch (std::exception&) + { return false; } } #if _DEBUG #include + void ExpressionEvaluator::RunTests() { //Some basic unit tests to run in debug mode - auto test = [=](string expr, EvalResultType expectedType, int expectedResult) { - DebugState state = { 0 }; - MemoryOperationInfo opInfo { 0, 0, MemoryOperationType::Read }; + auto test = [=](string expr, EvalResultType expectedType, int expectedResult) + { + DebugState state = {0}; + MemoryOperationInfo opInfo{0, 0, MemoryOperationType::Read}; EvalResultType type; int32_t result = Evaluate(expr, state, type, opInfo); assert(type == expectedType); assert(result == expectedResult); }; - + test("1 - -1", EvalResultType::Numeric, 2); test("1 - (-1)", EvalResultType::Numeric, 2); test("1 - -(-1)", EvalResultType::Numeric, 0); @@ -808,11 +1203,11 @@ void ExpressionEvaluator::RunTests() test("{$4500}", EvalResultType::Numeric, 0x4545); test("[$4500]", EvalResultType::Numeric, 0x45); - + test("[$45]3", EvalResultType::Invalid, 0); test("($45)3", EvalResultType::Invalid, 0); test("($45]", EvalResultType::Invalid, 0); - + test("%11", EvalResultType::Numeric, 3); test("%011", EvalResultType::Numeric, 3); test("%1011", EvalResultType::Numeric, 11); @@ -829,4 +1224,4 @@ void ExpressionEvaluator::RunTests() test("[$4500+[$4500]]", EvalResultType::Numeric, 0x45); test("-($10+[$4500])", EvalResultType::Numeric, -0x55); } -#endif \ No newline at end of file +#endif diff --git a/Core/ExpressionEvaluator.h b/Core/ExpressionEvaluator.h index 1821cee..9215138 100644 --- a/Core/ExpressionEvaluator.h +++ b/Core/ExpressionEvaluator.h @@ -39,8 +39,10 @@ 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, @@ -133,7 +135,7 @@ enum class EvalResultType : int32_t class StringHasher { public: - size_t operator()(const std::string& t) const + size_t operator()(const std::string& t) const { //Quick hash for expressions - most are likely to have different lengths, and not expecting dozens of breakpoints, either, so this should be fine. return t.size(); @@ -157,36 +159,40 @@ private: std::unordered_map _cache; SimpleLock _cacheLock; - + int64_t operandStack[1000]; Debugger* _debugger; LabelManager* _labelManager; 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 &opStack, std::stack &precedenceStack, vector &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& opStack, + std::stack& precedenceStack, vector& 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); #if _DEBUG void RunTests(); #endif -}; \ No newline at end of file +}; diff --git a/Core/FirmwareHelper.h b/Core/FirmwareHelper.h index 43f6371..254c863 100644 --- a/Core/FirmwareHelper.h +++ b/Core/FirmwareHelper.h @@ -14,20 +14,29 @@ struct MissingFirmwareMessage class FirmwareHelper { private: - static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &programRom, vector &dataRom, uint32_t programSize, uint32_t dataSize) + static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData, + vector& programRom, vector& dataRom, uint32_t programSize, + uint32_t dataSize) { - VirtualFile combinedFirmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename)); - if(combinedFirmware.GetSize() == programSize + dataSize) { + VirtualFile combinedFirmware( + FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename)); + if (combinedFirmware.GetSize() == programSize + dataSize) + { vector 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; @@ -35,11 +44,12 @@ private: } return false; } - + 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()); @@ -53,12 +63,14 @@ 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; @@ -68,13 +80,20 @@ private: } public: - static bool LoadDspFirmware(Console *console, FirmwareType type, string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &programRom, vector &dataRom, vector &embeddedFirware, uint32_t programSize = 0x1800, uint32_t dataSize = 0x800) + static bool LoadDspFirmware(Console* console, FirmwareType type, string combinedFilename, + string splitFilenameProgram, string splitFilenameData, vector& programRom, + vector& dataRom, vector& embeddedFirware, + uint32_t programSize = 0x1800, uint32_t dataSize = 0x800) { - if(embeddedFirware.size() == programSize + dataSize) { + 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; } @@ -85,7 +104,9 @@ 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; } @@ -95,17 +116,19 @@ 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; } @@ -117,7 +140,8 @@ public: { string filename = useSgb2 ? "SGB2.sfc" : "SGB1.sfc"; prgSize = useSgb2 ? 0x80000 : 0x40000; - if(AttemptLoadFirmware(prgRom, filename, prgSize)) { + if (AttemptLoadFirmware(prgRom, filename, prgSize)) + { return true; } @@ -127,7 +151,8 @@ public: msg.Size = prgSize; console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg); - if(AttemptLoadFirmware(prgRom, filename, prgSize)) { + if (AttemptLoadFirmware(prgRom, filename, prgSize)) + { return true; } @@ -139,16 +164,26 @@ public: { string filename; string altFilename; - 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; + 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; } uint32_t size = type == FirmwareType::GameboyColor ? 2304 : 256; - if(AttemptLoadFirmware(bootRom, filename, size, altFilename)) { + if (AttemptLoadFirmware(bootRom, filename, size, altFilename)) + { return true; } @@ -165,4 +200,4 @@ public: MessageManager::DisplayMessage("Error", "Could not find boot rom: " + filename);*/ return false; } -}; \ No newline at end of file +}; diff --git a/Core/ForceDisconnectMessage.h b/Core/ForceDisconnectMessage.h index 3378c78..8d12575 100644 --- a/Core/ForceDisconnectMessage.h +++ b/Core/ForceDisconnectMessage.h @@ -11,13 +11,15 @@ 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) { @@ -28,4 +30,4 @@ public: { return _disconnectMessage; } -}; \ No newline at end of file +}; diff --git a/Core/FrameLimiter.h b/Core/FrameLimiter.h index a3d04fd..ddf3fa1 100644 --- a/Core/FrameLimiter.h +++ b/Core/FrameLimiter.h @@ -25,7 +25,8 @@ 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) @@ -41,7 +42,8 @@ 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; @@ -50,4 +52,4 @@ public: _clockTimer.WaitUntil(_targetTime); return false; } -}; \ No newline at end of file +}; diff --git a/Core/GameClient.cpp b/Core/GameClient.cpp index 759e907..f6ae32c 100644 --- a/Core/GameClient.cpp +++ b/Core/GameClient.cpp @@ -21,7 +21,8 @@ GameClient::GameClient(shared_ptr console) GameClient::~GameClient() { _stop = true; - if(_clientThread) { + if (_clientThread) + { _clientThread->join(); } } @@ -32,13 +33,14 @@ bool GameClient::Connected() return instance ? instance->_connected : false; } -void GameClient::Connect(shared_ptr console, ClientConnectionData &connectionData) +void GameClient::Connect(shared_ptr console, ClientConnectionData& connectionData) { _instance.reset(new GameClient(console)); console->GetNotificationManager()->RegisterNotificationListener(_instance); - + shared_ptr instance = _instance; - if(instance) { + if (instance) + { instance->PrivateConnect(connectionData); instance->_clientThread.reset(new thread(&GameClient::Exec, instance.get())); } @@ -55,15 +57,18 @@ shared_ptr GameClient::GetConnection() return instance ? instance->_connection : nullptr; } -void GameClient::PrivateConnect(ClientConnectionData &connectionData) +void GameClient::PrivateConnect(ClientConnectionData& connectionData) { _stop = false; shared_ptr 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; } @@ -71,12 +76,17 @@ 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(); @@ -89,10 +99,11 @@ void GameClient::Exec() void GameClient::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded && - std::this_thread::get_id() != _clientThread->get_id() && + 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(); @@ -102,7 +113,8 @@ void GameClient::ProcessNotification(ConsoleNotificationType type, void* paramet void GameClient::SelectController(uint8_t port) { shared_ptr connection = GetConnection(); - if(connection) { + if (connection) + { connection->SelectController(port); } } @@ -117,4 +129,4 @@ uint8_t GameClient::GetControllerPort() { shared_ptr connection = GetConnection(); return connection ? connection->GetControllerPort() : GameConnection::SpectatorPort; -} \ No newline at end of file +} diff --git a/Core/GameClient.h b/Core/GameClient.h index 3774af1..8c7b34f 100644 --- a/Core/GameClient.h +++ b/Core/GameClient.h @@ -23,7 +23,7 @@ private: static shared_ptr 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, ClientConnectionData &connectionData); + static void Connect(shared_ptr console, ClientConnectionData& connectionData); static void Disconnect(); static void SelectController(uint8_t port); @@ -39,4 +39,4 @@ public: static uint8_t GetAvailableControllers(); void ProcessNotification(ConsoleNotificationType type, void* parameter) override; -}; \ No newline at end of file +}; diff --git a/Core/GameClientConnection.cpp b/Core/GameClientConnection.cpp index 8540eab..24887c4 100644 --- a/Core/GameClientConnection.cpp +++ b/Core/GameClientConnection.cpp @@ -17,7 +17,8 @@ #include "NotificationManager.h" #include "RomFinder.h" -GameClientConnection::GameClientConnection(shared_ptr console, shared_ptr socket, ClientConnectionData &connectionData) : GameConnection(console, socket) +GameClientConnection::GameClientConnection(shared_ptr console, shared_ptr socket, + ClientConnectionData& connectionData) : GameConnection(console, socket) { _connectionData = connectionData; _shutdown = false; @@ -34,12 +35,14 @@ GameClientConnection::~GameClientConnection() void GameClientConnection::Shutdown() { - if(!_shutdown) { + if (!_shutdown) + { _shutdown = true; DisableControllers(); shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->UnregisterInputProvider(this); } @@ -50,7 +53,9 @@ 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); } @@ -63,7 +68,8 @@ 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(); } @@ -73,80 +79,98 @@ void GameClientConnection::ProcessMessage(NetMessage* message) { GameInformationMessage* gameInfo; - switch(message->GetType()) { - case MessageType::ServerInformation: - _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt(); - SendHandshake(); - break; + switch (message->GetType()) + { + case MessageType::ServerInformation: + _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt(); + SendHandshake(); + break; - case MessageType::SaveState: - if(_gameLoaded) { - DisableControllers(); - _console->Lock(); - ClearInputData(); - ((SaveStateMessage*)message)->LoadState(_console); - _enableControllers = true; - InitControlDevice(); - _console->Unlock(); - } - break; - - case MessageType::MovieData: - if(_gameLoaded) { - PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), ((MovieDataMessage*)message)->GetInputState()); - } - break; - - case MessageType::ForceDisconnect: - MessageManager::DisplayMessage("NetPlay", ((ForceDisconnectMessage*)message)->GetMessage()); - break; - - case MessageType::PlayerList: - _playerList = ((PlayerListMessage*)message)->GetPlayerList(); - break; - - case MessageType::GameInformation: + case MessageType::SaveState: + if (_gameLoaded) + { DisableControllers(); _console->Lock(); - gameInfo = (GameInformationMessage*)message; - if(gameInfo->GetPort() != _controllerPort) { - _controllerPort = gameInfo->GetPort(); - - if(_controllerPort == GameConnection::SpectatorPort) { - MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator"); - } else { - MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1)); - } - } - ClearInputData(); + ((SaveStateMessage*)message)->LoadState(_console); + _enableControllers = true; + InitControlDevice(); _console->Unlock(); + } + break; - _gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash()); - if(!_gameLoaded) { - _console->Stop(true); - } else { - _console->GetControlManager()->UnregisterInputProvider(this); - _console->GetControlManager()->RegisterInputProvider(this); - if(gameInfo->IsPaused()) { - _console->Pause(); - } else { - _console->Resume(); - } + case MessageType::MovieData: + if (_gameLoaded) + { + PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), + ((MovieDataMessage*)message)->GetInputState()); + } + break; + + case MessageType::ForceDisconnect: + MessageManager::DisplayMessage("NetPlay", ((ForceDisconnectMessage*)message)->GetMessage()); + break; + + case MessageType::PlayerList: + _playerList = ((PlayerListMessage*)message)->GetPlayerList(); + break; + + case MessageType::GameInformation: + DisableControllers(); + _console->Lock(); + gameInfo = (GameInformationMessage*)message; + if (gameInfo->GetPort() != _controllerPort) + { + _controllerPort = gameInfo->GetPort(); + + if (_controllerPort == GameConnection::SpectatorPort) + { + MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator"); } - break; - default: - break; + else + { + MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1)); + } + } + + ClearInputData(); + _console->Unlock(); + + _gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash()); + if (!_gameLoaded) + { + _console->Stop(true); + } + else + { + _console->GetControlManager()->UnregisterInputProvider(this); + _console->GetControlManager()->RegisterInputProvider(this); + if (gameInfo->IsPaused()) + { + _console->Pause(); + } + else + { + _console->Resume(); + } + } + break; + default: + break; } } 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; } } @@ -159,7 +183,8 @@ 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(); } } @@ -169,30 +194,36 @@ 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; } @@ -200,10 +231,13 @@ 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); } @@ -215,33 +249,41 @@ 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; @@ -257,8 +299,10 @@ 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); } } @@ -268,4 +312,4 @@ uint8_t GameClientConnection::GetAvailableControllers() uint8_t GameClientConnection::GetControllerPort() { return _controllerPort; -} \ No newline at end of file +} diff --git a/Core/GameClientConnection.h b/Core/GameClientConnection.h index e963847..c9d2513 100644 --- a/Core/GameClientConnection.h +++ b/Core/GameClientConnection.h @@ -45,18 +45,18 @@ protected: void ProcessMessage(NetMessage* message) override; public: - GameClientConnection(shared_ptr console, shared_ptr socket, ClientConnectionData &connectionData); + GameClientConnection(shared_ptr console, shared_ptr 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(); void SelectController(uint8_t port); uint8_t GetAvailableControllers(); uint8_t GetControllerPort(); -}; \ No newline at end of file +}; diff --git a/Core/GameConnection.cpp b/Core/GameConnection.cpp index 1bbf10c..32f4d29 100644 --- a/Core/GameConnection.cpp +++ b/Core/GameConnection.cpp @@ -20,17 +20,20 @@ GameConnection::GameConnection(shared_ptr console, shared_ptr 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; @@ -38,8 +41,9 @@ 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; @@ -51,26 +55,29 @@ NetMessage* GameConnection::ReadMessage() { ReadSocket(); - if(_readPosition > 4) { + if (_readPosition > 4) + { uint32_t messageLength; - 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); - case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength); - case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength); - case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength); - case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength); - case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength); - case MessageType::ServerInformation: return new ServerInformationMessage(_messageBuffer, messageLength); + 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); + case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength); + case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength); + case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength); + case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength); + case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength); + case MessageType::ServerInformation: return new ServerInformationMessage(_messageBuffer, messageLength); } } } return nullptr; } -void GameConnection::SendNetMessage(NetMessage &message) +void GameConnection::SendNetMessage(NetMessage& message) { auto lock = _socketLock.AcquireSafe(); message.Send(*_socket.get()); @@ -90,10 +97,11 @@ 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); delete message; - } -} \ No newline at end of file + } +} diff --git a/Core/GameConnection.h b/Core/GameConnection.h index 95ec4be..88f76d9 100644 --- a/Core/GameConnection.h +++ b/Core/GameConnection.h @@ -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); -}; \ No newline at end of file + void SendNetMessage(NetMessage& message); +}; diff --git a/Core/GameInformationMessage.h b/Core/GameInformationMessage.h index e3eec0b..10f7a03 100644 --- a/Core/GameInformationMessage.h +++ b/Core/GameInformationMessage.h @@ -13,22 +13,25 @@ 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; _controllerPort = port; _paused = paused; } - + uint8_t GetPort() { return _controllerPort; @@ -48,4 +51,4 @@ public: { return _paused; } -}; \ No newline at end of file +}; diff --git a/Core/GameServer.cpp b/Core/GameServer.cpp index 50f7cb1..a452ab3 100644 --- a/Core/GameServer.cpp +++ b/Core/GameServer.cpp @@ -32,9 +32,10 @@ GameServer::~GameServer() _serverThread->join(); Stop(); - + shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->UnregisterInputRecorder(this); controlManager->UnregisterInputProvider(this); } @@ -43,7 +44,8 @@ GameServer::~GameServer() void GameServer::RegisterServerInput() { shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->RegisterInputRecorder(this); controlManager->RegisterInputProvider(this); } @@ -51,13 +53,17 @@ void GameServer::RegisterServerInput() void GameServer::AcceptConnections() { - while(true) { + while (true) + { shared_ptr socket = _listener->Accept(); - if(!socket->ConnectionError()) { + if (!socket->ConnectionError()) + { auto connection = shared_ptr(new GameServerConnection(_console, socket, _password)); _console->GetNotificationManager()->RegisterNotificationListener(connection); _openConnections.push_back(connection); - } else { + } + else + { break; } } @@ -67,48 +73,63 @@ void GameServer::AcceptConnections() void GameServer::UpdateConnections() { vector> connectionsToRemove; - for(shared_ptr connection : _openConnections) { - if(connection->ConnectionError()) { + for (shared_ptr connection : _openConnections) + { + if (connection->ConnectionError()) + { connectionsToRemove.push_back(connection); - } else { + } + else + { connection->ProcessMessages(); } } - for(shared_ptr gameConnection : connectionsToRemove) { + for (shared_ptr gameConnection : connectionsToRemove) + { _openConnections.remove(gameConnection); } } list> GameServer::GetConnectionList() { - if(GameServer::Started()) { + if (GameServer::Started()) + { return Instance->_openConnections; - } else { + } + else + { return list>(); } } -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; @@ -121,9 +142,12 @@ bool GameServer::SetInput(BaseControlDevice *device) void GameServer::RecordInput(vector> devices) { - for(shared_ptr &device : devices) { - for(shared_ptr connection : _openConnections) { - if(!connection->ConnectionError()) { + for (shared_ptr& device : devices) + { + for (shared_ptr connection : _openConnections) + { + if (!connection->ConnectionError()) + { //Send movie stream connection->SendMovieData(device->GetPort(), device->GetRawState()); } @@ -131,9 +155,10 @@ void GameServer::RecordInput(vector> 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(); } @@ -146,9 +171,10 @@ 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(); @@ -172,23 +198,28 @@ void GameServer::StartServer(shared_ptr 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 ""; @@ -196,7 +227,8 @@ string GameServer::GetHostPlayerName() uint8_t GameServer::GetHostControllerPort() { - if(GameServer::Started()) { + if (GameServer::Started()) + { return Instance->_hostControllerPort; } return GameConnection::SpectatorPort; @@ -204,9 +236,11 @@ 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(); @@ -218,8 +252,10 @@ 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); } } @@ -236,7 +272,8 @@ vector GameServer::GetPlayerList() playerInfo.IsHost = true; playerList.push_back(playerInfo); - for(shared_ptr &connection : GetConnectionList()) { + for (shared_ptr& connection : GetConnectionList()) + { playerInfo.Name = connection->GetPlayerName(); playerInfo.ControllerPort = connection->GetControllerPort(); playerInfo.IsHost = false; @@ -250,9 +287,10 @@ void GameServer::SendPlayerList() { vector playerList = GetPlayerList(); - for(shared_ptr &connection : GetConnectionList()) { + for (shared_ptr& connection : GetConnectionList()) + { //Send player list update to all connections PlayerListMessage message(playerList); connection->SendNetMessage(message); } -} \ No newline at end of file +} diff --git a/Core/GameServer.h b/Core/GameServer.h index 475519d..6b2a489 100644 --- a/Core/GameServer.h +++ b/Core/GameServer.h @@ -50,9 +50,9 @@ public: static list> GetConnectionList(); - bool SetInput(BaseControlDevice *device) override; + bool SetInput(BaseControlDevice* device) override; void RecordInput(vector> devices) override; // Inherited via INotificationListener - virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override; -}; \ No newline at end of file + virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) override; +}; diff --git a/Core/GameServerConnection.cpp b/Core/GameServerConnection.cpp index 7ae203e..6bd9fea 100644 --- a/Core/GameServerConnection.cpp +++ b/Core/GameServerConnection.cpp @@ -19,9 +19,10 @@ #include "BaseControlDevice.h" #include "ServerInformationMessage.h" -GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = { }; +GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = {}; -GameServerConnection::GameServerConnection(shared_ptr console, shared_ptr socket, string serverPassword) : GameConnection(console, socket) +GameServerConnection::GameServerConnection(shared_ptr console, shared_ptr socket, + string serverPassword) : GameConnection(console, socket) { //Server-side connection _serverPassword = serverPassword; @@ -31,8 +32,10 @@ GameServerConnection::GameServerConnection(shared_ptr 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); @@ -44,7 +47,8 @@ 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; } @@ -59,7 +63,8 @@ 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); @@ -68,7 +73,8 @@ void GameServerConnection::SendGameInformation() void GameServerConnection::SendMovieData(uint8_t port, ControlDeviceState state) { - if(_handshakeCompleted) { + if (_handshakeCompleted) + { MovieDataMessage message(state, port); SendNetMessage(message); } @@ -83,7 +89,8 @@ 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); } @@ -93,9 +100,11 @@ 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(); } @@ -106,18 +115,23 @@ 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(); } @@ -125,60 +139,77 @@ 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()) { - case MessageType::HandShake: - ProcessHandshakeResponse((HandShakeMessage*)message); - break; + switch (message->GetType()) + { + case MessageType::HandShake: + ProcessHandshakeResponse((HandShakeMessage*)message); + break; - case MessageType::InputData: - if(!_handshakeCompleted) { - SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); - return; - } - PushState(((InputDataMessage*)message)->GetInputState()); - break; + case MessageType::InputData: + if (!_handshakeCompleted) + { + SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); + return; + } + PushState(((InputDataMessage*)message)->GetInputState()); + break; - case MessageType::SelectController: - if(!_handshakeCompleted) { - SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); - return; - } - SelectControllerPort(((SelectControllerMessage*)message)->GetPortNumber()); - break; + case MessageType::SelectController: + if (!_handshakeCompleted) + { + SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); + return; + } + SelectControllerPort(((SelectControllerMessage*)message)->GetPortNumber()); + break; - default: - break; + default: + break; } } 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 } } @@ -189,26 +220,28 @@ void GameServerConnection::SelectControllerPort(uint8_t port) void GameServerConnection::ProcessNotification(ConsoleNotificationType type, void* parameter) { - switch(type) { - case ConsoleNotificationType::GamePaused: - case ConsoleNotificationType::GameLoaded: - case ConsoleNotificationType::GameResumed: - case ConsoleNotificationType::GameReset: - case ConsoleNotificationType::StateLoaded: - case ConsoleNotificationType::CheatsChanged: - case ConsoleNotificationType::ConfigChanged: - SendGameInformation(); - break; + switch (type) + { + case ConsoleNotificationType::GamePaused: + case ConsoleNotificationType::GameLoaded: + case ConsoleNotificationType::GameResumed: + case ConsoleNotificationType::GameReset: + case ConsoleNotificationType::StateLoaded: + case ConsoleNotificationType::CheatsChanged: + case ConsoleNotificationType::ConfigChanged: + SendGameInformation(); + break; - case ConsoleNotificationType::BeforeEmulationStop: { + case ConsoleNotificationType::BeforeEmulationStop: + { //Make clients unload the current game GameInformationMessage gameInfo("", "0000000000000000000000000000000000000000", _controllerPort, true); SendNetMessage(gameInfo); break; } - default: - break; + default: + break; } } @@ -219,9 +252,12 @@ 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; } @@ -237,8 +273,10 @@ 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; } } @@ -253,4 +291,4 @@ string GameServerConnection::GetPlayerName() uint8_t GameServerConnection::GetControllerPort() { return _controllerPort; -} \ No newline at end of file +} diff --git a/Core/GameServerConnection.h b/Core/GameServerConnection.h index 008df01..04a577a 100644 --- a/Core/GameServerConnection.h +++ b/Core/GameServerConnection.h @@ -15,7 +15,7 @@ private: list _inputData; string _playerName; - int _controllerPort; + int _controllerPort; string _connectionHash; string _serverPassword; bool _handshakeCompleted = false; @@ -35,7 +35,7 @@ private: protected: void ProcessMessage(NetMessage* message) override; - + public: GameServerConnection(shared_ptr console, shared_ptr socket, string serverPassword); virtual ~GameServerConnection(); diff --git a/Core/Gameboy.cpp b/Core/Gameboy.cpp index 1625d06..d96ee7b 100644 --- a/Core/Gameboy.cpp +++ b/Core/Gameboy.cpp @@ -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 romData; romFile.ReadFile(romData); @@ -31,22 +31,30 @@ 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; @@ -55,7 +63,8 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled return nullptr; } -void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData, GameboyHeader& header, bool sgbEnabled) +void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData, GameboyHeader& header, + bool sgbEnabled) { _console = console; _cart.reset(cart); @@ -71,15 +80,20 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData shared_ptr 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; } @@ -98,34 +112,42 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector& 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) { - default: - case GameboyModel::Gameboy: - _bootRom = new uint8_t[_bootRomSize]; - memcpy(_bootRom, dmgBootRom, _bootRomSize); - break; + if (!FirmwareHelper::LoadGbBootRom(console, &_bootRom, type)) + { + switch (_model) + { + default: + case GameboyModel::Gameboy: + _bootRom = new uint8_t[_bootRomSize]; + memcpy(_bootRom, dmgBootRom, _bootRomSize); + break; - case GameboyModel::GameboyColor: - _bootRom = new uint8_t[_bootRomSize]; - memcpy(_bootRom, cgbBootRom, _bootRomSize); - break; + case GameboyModel::GameboyColor: + _bootRom = new uint8_t[_bootRomSize]; + memcpy(_bootRom, cgbBootRom, _bootRomSize); + break; - case GameboyModel::SuperGameboy: - _bootRom = new uint8_t[_bootRomSize]; - if(cfg.UseSgb2) { - memcpy(_bootRom, sgb2BootRom, _bootRomSize); - } else { - memcpy(_bootRom, sgbBootRom, _bootRomSize); - } - break; + case GameboyModel::SuperGameboy: + _bootRom = new uint8_t[_bootRomSize]; + if (cfg.UseSgb2) + { + memcpy(_bootRom, sgb2BootRom, _bootRomSize); + } + else + { + memcpy(_bootRom, sgbBootRom, _bootRomSize); + } + break; } } @@ -154,7 +176,7 @@ Gameboy::~Gameboy() delete[] _cartRam; delete[] _prgRom; - + delete[] _spriteRam; delete[] _videoRam; @@ -184,21 +206,24 @@ 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); } } @@ -219,29 +244,31 @@ GbState Gameboy::GetState() uint32_t Gameboy::DebugGetMemorySize(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::GbPrgRom: return _prgRomSize; - case SnesMemoryType::GbWorkRam: return _workRamSize; - case SnesMemoryType::GbCartRam: return _cartRamSize; - case SnesMemoryType::GbHighRam: return Gameboy::HighRamSize; - case SnesMemoryType::GbBootRom: return _bootRomSize; - case SnesMemoryType::GbVideoRam: return _videoRamSize; - case SnesMemoryType::GbSpriteRam: return Gameboy::SpriteRamSize; - default: return 0; + switch (type) + { + case SnesMemoryType::GbPrgRom: return _prgRomSize; + case SnesMemoryType::GbWorkRam: return _workRamSize; + case SnesMemoryType::GbCartRam: return _cartRamSize; + case SnesMemoryType::GbHighRam: return Gameboy::HighRamSize; + case SnesMemoryType::GbBootRom: return _bootRomSize; + case SnesMemoryType::GbVideoRam: return _videoRamSize; + case SnesMemoryType::GbSpriteRam: return Gameboy::SpriteRamSize; + default: return 0; } } uint8_t* Gameboy::DebugGetMemory(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::GbPrgRom: return _prgRom; - case SnesMemoryType::GbWorkRam: return _workRam; - case SnesMemoryType::GbCartRam: return _cartRam; - case SnesMemoryType::GbHighRam: return _highRam; - case SnesMemoryType::GbBootRom: return _bootRom; - case SnesMemoryType::GbVideoRam: return _videoRam; - case SnesMemoryType::GbSpriteRam: return _spriteRam; - default: return nullptr; + switch (type) + { + case SnesMemoryType::GbPrgRom: return _prgRom; + case SnesMemoryType::GbWorkRam: return _workRam; + case SnesMemoryType::GbCartRam: return _cartRam; + case SnesMemoryType::GbHighRam: return _highRam; + case SnesMemoryType::GbBootRom: return _bootRom; + case SnesMemoryType::GbVideoRam: return _videoRam; + case SnesMemoryType::GbSpriteRam: return _spriteRam; + default: return nullptr; } } @@ -260,16 +287,17 @@ 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; @@ -277,22 +305,30 @@ 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; } @@ -301,13 +337,16 @@ 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); } } diff --git a/Core/Gameboy.h b/Core/Gameboy.h index 518a940..4e0aa78 100644 --- a/Core/Gameboy.h +++ b/Core/Gameboy.h @@ -68,13 +68,13 @@ public: void Exec(); void Run(uint64_t runUntilClock); - + void LoadBattery(); void SaveBattery(); GbPpu* GetPpu(); GbCpu* GetCpu(); - void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); + void GetSoundSamples(int16_t* & samples, uint32_t& sampleCount); GbState GetState(); GameboyHeader GetHeader(); @@ -94,4 +94,4 @@ public: void Serialize(Serializer& s) override; void SetReg(GbRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/GameboyDisUtils.cpp b/Core/GameboyDisUtils.cpp index 05f01da..eb7805b 100644 --- a/Core/GameboyDisUtils.cpp +++ b/Core/GameboyDisUtils.cpp @@ -8,127 +8,205 @@ #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 { None, BC, - DE, + DE, HL, C, Suff }; 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++; } @@ -138,19 +216,21 @@ void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_ int32_t GameboyDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, GbCpuState& state) { - switch(_gbEffAddrType[info.GetOpCode()]) { - default: - case AddrType::None: return -1; + switch (_gbEffAddrType[info.GetOpCode()]) + { + default: + case AddrType::None: return -1; - case AddrType::BC: return (state.B << 8) | state.C; - case AddrType::DE: return (state.D << 8) | state.E; - 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) { - return (state.H << 8) | state.L; - } - return -1; + case AddrType::BC: return (state.B << 8) | state.C; + case AddrType::DE: return (state.D << 8) | state.E; + 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) + { + return (state.H << 8) | state.L; + } + return -1; } } @@ -163,8 +243,9 @@ 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 ); } @@ -179,4 +260,4 @@ bool GameboyDisUtils::IsReturnInstruction(uint8_t opCode) string GameboyDisUtils::GetOpTemplate(uint8_t op, bool prefixed) { return prefixed ? _cbTemplate[op] : _opTemplate[op]; -} \ No newline at end of file +} diff --git a/Core/GameboyDisUtils.h b/Core/GameboyDisUtils.h index eaf670b..0eb5b1d 100644 --- a/Core/GameboyDisUtils.h +++ b/Core/GameboyDisUtils.h @@ -10,7 +10,8 @@ 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); diff --git a/Core/GameboyHeader.h b/Core/GameboyHeader.h index 108eb76..5c0fc46 100644 --- a/Core/GameboyHeader.h +++ b/Core/GameboyHeader.h @@ -20,7 +20,8 @@ struct GameboyHeader uint32_t GetPrgRomSize() { - if(PrgRomSize < 16) { + if (PrgRomSize < 16) + { return 0x8000 << PrgRomSize; } return 0x8000; @@ -28,29 +29,40 @@ 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) { - case 0: return 0; - case 1: return 0x800; - case 2: return 0x2000; - case 3: return 0x8000; - case 4: return 0x20000; - case 5: return 0x10000; + switch (CartRamSize) + { + case 0: return 0; + case 1: return 0x800; + case 2: return 0x2000; + case 3: return 0x8000; + case 4: return 0x20000; + case 5: return 0x10000; } return 0; } 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: - return true; + 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; } return false; @@ -59,8 +71,10 @@ 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; } @@ -68,9 +82,12 @@ 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; } } diff --git a/Core/GbApu.cpp b/Core/GbApu.cpp index 3a77a76..a69e1e7 100644 --- a/Core/GbApu.cpp +++ b/Core/GbApu.cpp @@ -37,10 +37,13 @@ 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); } @@ -72,11 +75,18 @@ void GbApu::Run() GameboyConfig cfg = _settings->GetGameboyConfig(); - if(!_state.ApuEnabled) { + if (!_state.ApuEnabled) + { _clockCounter += clocksToRun; - } else { - while(clocksToRun > 0) { - uint32_t minTimer = std::min({ clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, _noise->GetState().Timer }); + } + else + { + while (clocksToRun > 0) + { + uint32_t minTimer = std::min({ + clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, + _noise->GetState().Timer + }); clocksToRun -= minTimer; _square1->Exec(minTimer); @@ -89,9 +99,10 @@ void GbApu::Run() (_square2->GetOutput() & _state.EnableLeftSq2) * cfg.Square2Vol / 100 + (_wave->GetOutput() & _state.EnableLeftWave) * cfg.WaveVol / 100 + (_noise->GetOutput() & _state.EnableLeftNoise) * cfg.NoiseVol / 100 - ) * (_state.LeftVolume + 1) * 40; + ) * (_state.LeftVolume + 1) * 40; - if(_prevLeftOutput != leftOutput) { + if (_prevLeftOutput != leftOutput) + { blip_add_delta(_leftChannel, _clockCounter, leftOutput - _prevLeftOutput); _prevLeftOutput = leftOutput; } @@ -101,9 +112,10 @@ void GbApu::Run() (_square2->GetOutput() & _state.EnableRightSq2) * cfg.Square2Vol / 100 + (_wave->GetOutput() & _state.EnableRightWave) * cfg.WaveVol / 100 + (_noise->GetOutput() & _state.EnableRightNoise) * cfg.NoiseVol / 100 - ) * (_state.RightVolume + 1) * 40; + ) * (_state.RightVolume + 1) * 40; - if(_prevRightOutput != rightOutput) { + if (_prevRightOutput != rightOutput) + { blip_add_delta(_rightChannel, _clockCounter, rightOutput - _prevRightOutput); _prevRightOutput = rightOutput; } @@ -112,7 +124,8 @@ void GbApu::Run() } } - if(!_gameboy->IsSgb() && _clockCounter >= 20000) { + if (!_gameboy->IsSgb() && _clockCounter >= 20000) + { blip_end_frame(_leftChannel, _clockCounter); blip_end_frame(_rightChannel, _clockCounter); @@ -123,7 +136,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); @@ -139,20 +152,25 @@ 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(); @@ -174,52 +192,81 @@ 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: - return _square1->Read(addr - 0xFF10); - - case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19: - return _square2->Read(addr - 0xFF15); + switch (addr) + { + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + return _square1->Read(addr - 0xFF10); - case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E: - return _wave->Read(addr - 0xFF1A); + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + return _square2->Read(addr - 0xFF15); - case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - return _noise->Read(addr - 0xFF1F); + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + return _wave->Read(addr - 0xFF1A); - case 0xFF24: - return ( - (_state.ExtAudioLeftEnabled ? 0x80 : 0) | - (_state.LeftVolume << 4) | - (_state.ExtAudioRightEnabled ? 0x08 : 0) | - _state.RightVolume - ); + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + return _noise->Read(addr - 0xFF1F); - case 0xFF25: - return ( - (_state.EnableLeftNoise ? 0x80 : 0) | - (_state.EnableLeftWave ? 0x40 : 0) | - (_state.EnableLeftSq2 ? 0x20 : 0) | - (_state.EnableLeftSq1 ? 0x10 : 0) | - (_state.EnableRightNoise ? 0x08 : 0) | - (_state.EnableRightWave ? 0x04 : 0) | - (_state.EnableRightSq2 ? 0x02 : 0) | - (_state.EnableRightSq1 ? 0x01 : 0) - ); + case 0xFF24: + return ( + (_state.ExtAudioLeftEnabled ? 0x80 : 0) | + (_state.LeftVolume << 4) | + (_state.ExtAudioRightEnabled ? 0x08 : 0) | + _state.RightVolume + ); - case 0xFF26: - return ( - (_state.ApuEnabled ? 0x80 : 0) | - 0x70 | //open bus - ((_state.ApuEnabled && _noise->Enabled()) ? 0x08 : 0) | - ((_state.ApuEnabled && _wave->Enabled()) ? 0x04 : 0) | - ((_state.ApuEnabled && _square2->Enabled()) ? 0x02 : 0) | - ((_state.ApuEnabled && _square1->Enabled()) ? 0x01 : 0) - ); + case 0xFF25: + return ( + (_state.EnableLeftNoise ? 0x80 : 0) | + (_state.EnableLeftWave ? 0x40 : 0) | + (_state.EnableLeftSq2 ? 0x20 : 0) | + (_state.EnableLeftSq1 ? 0x10 : 0) | + (_state.EnableRightNoise ? 0x08 : 0) | + (_state.EnableRightWave ? 0x04 : 0) | + (_state.EnableRightSq2 ? 0x02 : 0) | + (_state.EnableRightSq1 ? 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: - return _wave->ReadRam(addr); + case 0xFF26: + return ( + (_state.ApuEnabled ? 0x80 : 0) | + 0x70 | //open bus + ((_state.ApuEnabled && _noise->Enabled()) ? 0x08 : 0) | + ((_state.ApuEnabled && _wave->Enabled()) ? 0x04 : 0) | + ((_state.ApuEnabled && _square2->Enabled()) ? 0x02 : 0) | + ((_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: + return _wave->ReadRam(addr); } //Open bus @@ -230,63 +277,87 @@ 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: - _square1->Write(addr - 0xFF10, value); - break; + 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: - _square2->Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit - break; + 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: - _wave->Write(addr - 0xFF1A, value); - break; + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + _wave->Write(addr - 0xFF1A, value); + break; - case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - _noise->Write(addr - 0xFF1F, value); - break; + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + _noise->Write(addr - 0xFF1F, value); + break; - case 0xFF24: - _state.ExtAudioLeftEnabled = (value & 0x80) != 0; - _state.LeftVolume = (value & 0x70) >> 4; - _state.ExtAudioRightEnabled = (value & 0x08) != 0; - _state.RightVolume = (value & 0x07); - break; + case 0xFF24: + _state.ExtAudioLeftEnabled = (value & 0x80) != 0; + _state.LeftVolume = (value & 0x70) >> 4; + _state.ExtAudioRightEnabled = (value & 0x08) != 0; + _state.RightVolume = (value & 0x07); + break; - case 0xFF25: - _state.EnableLeftNoise = (value & 0x80) ? 0xFF : 0; - _state.EnableLeftWave = (value & 0x40) ? 0xFF : 0; - _state.EnableLeftSq2 = (value & 0x20) ? 0xFF : 0; - _state.EnableLeftSq1 = (value & 0x10) ? 0xFF : 0; + case 0xFF25: + _state.EnableLeftNoise = (value & 0x80) ? 0xFF : 0; + _state.EnableLeftWave = (value & 0x40) ? 0xFF : 0; + _state.EnableLeftSq2 = (value & 0x20) ? 0xFF : 0; + _state.EnableLeftSq1 = (value & 0x10) ? 0xFF : 0; - _state.EnableRightNoise = (value & 0x08) ? 0xFF : 0; - _state.EnableRightWave = (value & 0x04) ? 0xFF : 0; - _state.EnableRightSq2 = (value & 0x02) ? 0xFF : 0; - _state.EnableRightSq1 = (value & 0x01) ? 0xFF : 0; - break; + _state.EnableRightNoise = (value & 0x08) ? 0xFF : 0; + _state.EnableRightWave = (value & 0x04) ? 0xFF : 0; + _state.EnableRightSq2 = (value & 0x02) ? 0xFF : 0; + _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; @@ -295,38 +366,59 @@ 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: - _wave->WriteRam(addr, 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: + _wave->WriteRam(addr, value); + break; } } uint8_t GbApu::ReadCgbRegister(uint16_t addr) { - switch(addr) { - case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4); - case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4); + switch (addr) + { + case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4); + case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4); } //Should not be called return 0; } -template -void GbApu::ProcessLengthEnableFlag(uint8_t value, T &length, bool &lengthEnabled, bool &enabled) +template +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; } } @@ -351,5 +443,7 @@ void GbApu::Serialize(Serializer& s) s.Stream(_noise.get()); } -template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint8_t& length, bool& lengthEnabled, bool& enabled); -template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint16_t& length, bool& lengthEnabled, bool& enabled); \ No newline at end of file +template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint8_t& length, bool& lengthEnabled, + bool& enabled); +template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint16_t& length, bool& lengthEnabled, + bool& enabled); diff --git a/Core/GbApu.h b/Core/GbApu.h index ca13e6f..3953396 100644 --- a/Core/GbApu.h +++ b/Core/GbApu.h @@ -52,7 +52,7 @@ public: void Run(); - void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); + void GetSoundSamples(int16_t* & samples, uint32_t& sampleCount); void ClockFrameSequencer(); @@ -62,7 +62,8 @@ public: uint8_t ReadCgbRegister(uint16_t addr); - template void ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled); + template + void ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled); void Serialize(Serializer& s) override; }; diff --git a/Core/GbAssembler.cpp b/Core/GbAssembler.cpp index 0470415..53c9614 100644 --- a/Core/GbAssembler.cpp +++ b/Core/GbAssembler.cpp @@ -20,17 +20,21 @@ GbAssembler::~GbAssembler() void GbAssembler::InitAssembler() { - for(int i = 0; i < 512; i++) { + for (int i = 0; i < 512; i++) + { string op = GameboyDisUtils::GetOpTemplate(i & 0xFF, i >= 256); size_t spaceIndex = op.find(' '); size_t commaIndex = op.find(','); string opName; OpCodeEntry entry = {}; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { opName = op.substr(0, spaceIndex); entry.ParamCount = commaIndex != string::npos ? 2 : 1; - } else { + } + else + { opName = op; entry.ParamCount = 0; } @@ -38,18 +42,23 @@ void GbAssembler::InitAssembler() entry.OpCode = i < 256 ? i : ((i << 8) | 0xCB); std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower); - if(_opCodes.find(opName) == _opCodes.end()) { + if (_opCodes.find(opName) == _opCodes.end()) + { _opCodes[opName] = vector(); } - if(entry.ParamCount > 0) { + if (entry.ParamCount > 0) + { string operands = op.substr(spaceIndex + 1); operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end()); - if(entry.ParamCount == 2) { + if (entry.ParamCount == 2) + { vector operandList = StringUtilities::Split(operands, ','); InitParamEntry(entry.Param1, operandList[0]); InitParamEntry(entry.Param2, operandList[1]); - } else if(entry.ParamCount == 1) { + } + else if (entry.ParamCount == 1) + { InitParamEntry(entry.Param1, operands); } } @@ -59,21 +68,36 @@ void GbAssembler::InitAssembler() void GbAssembler::InitParamEntry(ParamEntry& entry, string param) { - if(param == "a") { + if (param == "a") + { entry.Type = ParamType::Short; - } else if(param == "d") { + } + else if (param == "d") + { entry.Type = ParamType::Byte; - } else if(param == "e") { + } + else if (param == "e") + { entry.Type = ParamType::Short; - } else if(param == "r") { + } + else if (param == "r") + { entry.Type = ParamType::RelAddress; - } else if(param == "(a)") { + } + else if (param == "(a)") + { entry.Type = ParamType::Address; - } else if(param == "(c)") { + } + else if (param == "(c)") + { entry.Type = ParamType::HighAddress; - } else if(param == "SP+d") { + } + else if (param == "SP+d") + { entry.Type = ParamType::StackOffset; - } else { + } + else + { std::transform(param.begin(), param.end(), param.begin(), ::tolower); entry.Type = ParamType::Literal; entry.Param = param; @@ -83,111 +107,143 @@ void GbAssembler::InitParamEntry(ParamEntry& entry, string param) bool GbAssembler::IsRegisterName(string op) { - return op == "hl" || op == "af" || op == "bc" || op == "de" || op == "a" || op == "b" || op == "c" || op == "d" || op == "e" || op == "f" || op == "l" || op == "h"; + return op == "hl" || op == "af" || op == "bc" || op == "de" || op == "a" || op == "b" || op == "c" || op == "d" || op + == "e" || op == "f" || op == "l" || op == "h"; } -int GbAssembler::ReadValue(string operand, int min, int max, unordered_map& localLabels, bool firstPass) +int GbAssembler::ReadValue(string operand, int min, int max, unordered_map& localLabels, + bool firstPass) { int value = 0; - switch(operand[0]) { + switch (operand[0]) + { //Hex - case '$': value = HexUtilities::FromHex(operand.substr(1)); break; + case '$': value = HexUtilities::FromHex(operand.substr(1)); + break; - case '%': - //Binary - for(size_t i = 1; i < operand.size(); i++) { - value <<= 1; - value |= operand[i] == '1' ? 1 : 0; + case '%': + //Binary + for (size_t i = 1; i < operand.size(); i++) + { + value <<= 1; + value |= operand[i] == '1' ? 1 : 0; + } + break; + + default: + if (std::regex_match(operand, labelRegex)) + { + if (firstPass) + { + return 0; } - break; - - default: - if(std::regex_match(operand, labelRegex)) { - if(firstPass) { - return 0; - } else if(localLabels.find(operand) != localLabels.end()) { - value = localLabels.find(operand)->second; - } else { - int labelAddress = _labelManager->GetLabelRelativeAddress(operand, CpuType::Gameboy); - if(labelAddress >= 0) { - //Matching label found - value = labelAddress; - } + else if (localLabels.find(operand) != localLabels.end()) + { + value = localLabels.find(operand)->second; + } + else + { + int labelAddress = _labelManager->GetLabelRelativeAddress(operand, CpuType::Gameboy); + if (labelAddress >= 0) + { + //Matching label found + value = labelAddress; } - } else { - //Decimal - for(size_t i = 0; i < operand.size(); i++) { - if(operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) { - return -1; - } - } - - try { - value = std::stoi(operand); - if(value < 0) { - value = max + value + 1; - } - } catch(std::exception&) { + } + } + else + { + //Decimal + for (size_t i = 0; i < operand.size(); i++) + { + if (operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) + { return -1; } } - break; + + try + { + value = std::stoi(operand); + if (value < 0) + { + value = max + value + 1; + } + } + catch (std::exception&) + { + return -1; + } + } + break; } - if(value < min || value > max) { + if (value < min || value > max) + { return -1; } return value; } -bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, bool firstPass) +bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, + unordered_map& localLabels, bool firstPass) { - if(entry.Type != ParamType::Literal && IsRegisterName(operand)) { + if (entry.Type != ParamType::Literal && IsRegisterName(operand)) + { return false; } - switch(entry.Type) { - case ParamType::None: return false; + switch (entry.Type) + { + case ParamType::None: return false; - case ParamType::Literal: { + case ParamType::Literal: + { string param = entry.Param; std::transform(param.begin(), param.end(), param.begin(), ::tolower); std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); return operand == param; } - case ParamType::Byte: - return ReadValue(operand, -128, 0xFF, localLabels, firstPass) >= 0; + case ParamType::Byte: + return ReadValue(operand, -128, 0xFF, localLabels, firstPass) >= 0; - case ParamType::Short: - return ReadValue(operand, -32768, 0xFFFF, localLabels, firstPass) >= 0; + case ParamType::Short: + return ReadValue(operand, -32768, 0xFFFF, localLabels, firstPass) >= 0; - case ParamType::Address: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - return ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::Address: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + return ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::HighAddress: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - return ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::HighAddress: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + return ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::StackOffset: - std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); - if(operand.size() > 3 && operand.substr(0, 3) == "sp+") { - return ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::StackOffset: + std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); + if (operand.size() > 3 && operand.substr(0, 3) == "sp+") + { + return ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::RelAddress: { + case ParamType::RelAddress: + { int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass); - if(value >= 0) { + if (value >= 0) + { int offset = (value - (address + 2)); return offset >= -128 && offset <= 127; - } else if(firstPass) { + } + else if (firstPass) + { return 0; } return false; @@ -199,9 +255,12 @@ bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, u void GbAssembler::PushOp(uint16_t opCode, vector& output, uint32_t& address) { - if(opCode < 256) { + if (opCode < 256) + { PushByte((uint8_t)opCode, output, address); - } else { + } + else + { PushWord((uint16_t)opCode, output, address); } } @@ -219,40 +278,48 @@ void GbAssembler::PushWord(uint16_t operand, vector& output, uint32_t& address += 2; } -void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, unordered_map& localLabels, bool firstPass) +void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, + unordered_map& localLabels, bool firstPass) { - switch(entry.Type) { - default: - break; + switch (entry.Type) + { + default: + break; - case ParamType::Byte: - PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address); - break; + case ParamType::Byte: + PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address); + break; - case ParamType::Short: - PushWord((uint16_t)ReadValue(operand, -32768, 65535, localLabels, firstPass), output, address); - break; + case ParamType::Short: + PushWord((uint16_t)ReadValue(operand, -32768, 65535, localLabels, firstPass), output, address); + break; - case ParamType::Address: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - PushWord((uint16_t)ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass), output, address); - } - break; + case ParamType::Address: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + PushWord((uint16_t)ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass), output, + address); + } + break; - case ParamType::HighAddress: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - PushByte((uint8_t)ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass), output, address); - } - break; + case ParamType::HighAddress: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + PushByte((uint8_t)ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass), + output, address); + } + break; - case ParamType::StackOffset: - std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); - if(operand.size() > 3 && operand.substr(0, 3) == "sp+") { - PushByte((uint8_t)ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass), output, address); - } - break; + case ParamType::StackOffset: + std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); + if (operand.size() > 3 && operand.substr(0, 3) == "sp+") + { + PushByte((uint8_t)ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass), output, address); + } + break; - case ParamType::RelAddress: { + case ParamType::RelAddress: + { int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass); int offset = (value - (address + 1)); PushByte((uint8_t)offset, output, address); @@ -261,32 +328,42 @@ void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, unordered_map& localLabels) +void GbAssembler::RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, + bool firstPass, unordered_map& localLabels) { unordered_set currentPassLabels; - for(string line : StringUtilities::Split(code, '\n')) { + for (string line : StringUtilities::Split(code, '\n')) + { //Remove comment size_t commentIndex = line.find(';'); - if(commentIndex != string::npos) { + if (commentIndex != string::npos) + { line = line.substr(0, commentIndex); } //Check if this is a label definition size_t labelDefIndex = line.find(':'); - if(labelDefIndex != string::npos) { + if (labelDefIndex != string::npos) + { std::smatch match; string labelName = line.substr(0, labelDefIndex); - if(std::regex_search(labelName, match, labelRegex)) { + if (std::regex_search(labelName, match, labelRegex)) + { string label = match.str(1); - if(firstPass && currentPassLabels.find(label) != currentPassLabels.end()) { + if (firstPass && currentPassLabels.find(label) != currentPassLabels.end()) + { output.push_back(AssemblerSpecialCodes::LabelRedefinition); continue; - } else { + } + else + { localLabels[label] = address; currentPassLabels.emplace(label); line = line.substr(labelDefIndex + 1); } - } else { + } + else + { output.push_back(AssemblerSpecialCodes::InvalidLabel); continue; } @@ -294,20 +371,25 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Trim left spaces size_t startIndex = line.find_first_not_of("\t "); - if(startIndex > 0 && startIndex != string::npos) { + if (startIndex > 0 && startIndex != string::npos) + { line = line.substr(startIndex); } //Check if this is a .db statement - if(line.size() > 3 && line.substr(0, 3) == ".db") { + if (line.size() > 3 && line.substr(0, 3) == ".db") + { line = line.substr(3); - for(string byte : StringUtilities::Split(line, ' ')) { - if(byte.empty()) { + for (string byte : StringUtilities::Split(line, ' ')) + { + if (byte.empty()) + { continue; } int value = ReadValue(byte, -128, 255, localLabels, true); - if(value >= 0) { + if (value >= 0) + { PushByte((uint8_t)value, output, address); } } @@ -318,20 +400,25 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Find op code name size_t spaceIndex = line.find(' '); string opName; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { opName = line.substr(0, spaceIndex); - } else { + } + else + { opName = line; } - if(opName.empty()) { + if (opName.empty()) + { output.push_back(AssemblerSpecialCodes::EndOfLine); continue; } std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower); - if(_opCodes.find(opName) == _opCodes.end()) { + if (_opCodes.find(opName) == _opCodes.end()) + { //No matching opcode found, mark it as invalid output.push_back(AssemblerSpecialCodes::InvalidInstruction); continue; @@ -340,51 +427,69 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Find the operands given int paramCount = 0; vector operandList; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { string operands = line.substr(spaceIndex + 1); operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end()); - if(!operands.empty()) { + if (!operands.empty()) + { size_t commaIndex = line.find(','); - if(commaIndex != string::npos) { + if (commaIndex != string::npos) + { paramCount = 2; operandList = StringUtilities::Split(operands, ','); bool invalid = operandList.size() > 2; - for(string operand : operandList) { - if(operand.empty()) { + for (string operand : operandList) + { + if (operand.empty()) + { invalid = true; break; } } - if(invalid) { + if (invalid) + { output.push_back(AssemblerSpecialCodes::InvalidOperands); continue; } - } else { + } + else + { paramCount = 1; - operandList = { operands }; + operandList = {operands}; } } } bool matchFound = false; //Find a matching set of opcode + operands - for(OpCodeEntry& entry : _opCodes.find(opName)->second) { - if(entry.ParamCount == paramCount) { - if(paramCount == 0) { + for (OpCodeEntry& entry : _opCodes.find(opName)->second) + { + if (entry.ParamCount == paramCount) + { + if (paramCount == 0) + { PushOp(entry.OpCode, output, address); matchFound = true; break; - } else if(paramCount == 1) { - if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass)) { + } + else if (paramCount == 1) + { + if (IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass)) + { PushOp(entry.OpCode, output, address); ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass); matchFound = true; break; } - } else if(paramCount == 2) { - if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass) && IsMatch(entry.Param2, operandList[1], address, localLabels, firstPass)) { + } + else if (paramCount == 2) + { + if (IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass) && IsMatch( + entry.Param2, operandList[1], address, localLabels, firstPass)) + { PushOp(entry.OpCode, output, address); ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass); ProcessOperand(entry.Param2, operandList[1], output, address, localLabels, firstPass); @@ -395,9 +500,12 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address } } - if(!matchFound) { + if (!matchFound) + { output.push_back(AssemblerSpecialCodes::InvalidOperands); - } else { + } + else + { output.push_back(AssemblerSpecialCodes::EndOfLine); } } diff --git a/Core/GbAssembler.h b/Core/GbAssembler.h index e18dca3..32be9ea 100644 --- a/Core/GbAssembler.h +++ b/Core/GbAssembler.h @@ -40,17 +40,20 @@ private: bool IsRegisterName(string op); void InitAssembler(); int ReadValue(string operand, int min, int max, unordered_map& localLabels, bool firstPass); - bool IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, bool firstPass); + bool IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, + bool firstPass); void PushOp(uint16_t opCode, vector& output, uint32_t& address); void PushByte(uint8_t operand, vector& output, uint32_t& address); void PushWord(uint16_t operand, vector& output, uint32_t& address); - void ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, unordered_map& localLabels, bool firstPass); + void ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, + unordered_map& localLabels, bool firstPass); - void RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, unordered_map& localLabels); + void RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, + unordered_map& localLabels); public: GbAssembler(shared_ptr labelManager); virtual ~GbAssembler(); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); -}; \ No newline at end of file +}; diff --git a/Core/GbCart.h b/Core/GbCart.h index d6fe052..e51c592 100644 --- a/Core/GbCart.h +++ b/Core/GbCart.h @@ -12,7 +12,7 @@ protected: Gameboy* _gameboy = nullptr; GbMemoryManager* _memoryManager = nullptr; uint8_t* _cartRam = nullptr; - + void Map(uint16_t start, uint16_t end, GbMemoryType type, uint32_t offset, bool readonly) { _memoryManager->Map(start, end, type, offset, readonly); diff --git a/Core/GbCartFactory.h b/Core/GbCartFactory.h index 0eeeb86..1744446 100644 --- a/Core/GbCartFactory.h +++ b/Core/GbCartFactory.h @@ -11,24 +11,36 @@ class GbCartFactory public: static GbCart* CreateCart(uint8_t cartType) { - switch(cartType) { - case 0: - return new GbCart(); + switch (cartType) + { + case 0: + return new GbCart(); - case 1: case 2: case 3: - return new GbMbc1(); + case 1: + case 2: + case 3: + return new GbMbc1(); - case 5: case 6: - return new GbMbc2(); + case 5: + case 6: + return new GbMbc2(); - case 15: case 16: - return new GbMbc3(true); + case 15: + case 16: + return new GbMbc3(true); - case 17: case 18: case 19: - return new GbMbc3(false); + case 17: + case 18: + case 19: + return new GbMbc3(false); - case 25: case 26: case 27: case 28: case 29: case 30: - return new GbMbc5(); + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + return new GbMbc5(); }; return nullptr; diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index a4b20f9..ad7995f 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -10,7 +10,7 @@ void GbCpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana _console = console; _gameboy = gameboy; _memoryManager = memoryManager; - + _state = {}; _state.PC = 0; @@ -34,8 +34,10 @@ bool GbCpu::IsHalted() void GbCpu::Exec() { uint8_t irqVector = _memoryManager->ProcessIrqRequests(); - if(irqVector) { - if(_state.IME) { + if (irqVector) + { + if (_state.IME) + { uint16_t oldPc = _state.PC; IncCycleCount(); IncCycleCount(); @@ -45,20 +47,27 @@ void GbCpu::Exec() PushByte((uint8_t)_state.PC); IncCycleCount(); - - switch(irqVector) { - case 0: - //IRQ request bit is no longer set, jump to $0000 (ie_push test) - _state.PC = 0; - break; - case GbIrqSource::VerticalBlank: _state.PC = 0x40; break; - case GbIrqSource::LcdStat: _state.PC = 0x48; break; - case GbIrqSource::Timer: _state.PC = 0x50; break; - case GbIrqSource::Serial: _state.PC = 0x58; break; - case GbIrqSource::Joypad: _state.PC = 0x60; break; + switch (irqVector) + { + case 0: + //IRQ request bit is no longer set, jump to $0000 (ie_push test) + _state.PC = 0; + break; + + case GbIrqSource::VerticalBlank: _state.PC = 0x40; + break; + case GbIrqSource::LcdStat: _state.PC = 0x48; + break; + case GbIrqSource::Timer: _state.PC = 0x50; + break; + case GbIrqSource::Serial: _state.PC = 0x58; + break; + case GbIrqSource::Joypad: _state.PC = 0x60; + break; } - if(irqVector) { + if (irqVector) + { //Only clear IRQ bit if an IRQ was processed _memoryManager->ClearIrqRequest(irqVector); } @@ -69,12 +78,14 @@ void GbCpu::Exec() _state.Halted = false; } - if(_state.Halted) { + if (_state.Halted) + { IncCycleCount(); return; } - if(_state.EiPending) { + if (_state.EiPending) + { _state.EiPending = false; _state.IME = true; } @@ -84,263 +95,525 @@ void GbCpu::Exec() void GbCpu::ExecOpCode(uint8_t opCode) { - switch(opCode) { - case 0x00: NOP(); break; - case 0x01: LD(_regBC, ReadCodeWord()); break; - case 0x02: LD_Indirect(_regBC, _state.A); break; - case 0x03: INC(_regBC); break; - case 0x04: INC(_state.B); break; - case 0x05: DEC(_state.B); break; - case 0x06: LD(_state.B, ReadCode()); break; - case 0x07: RLCA(); break; - case 0x08: LD_Indirect16(ReadCodeWord(), _state.SP); break; - case 0x09: ADD(_regHL, _regBC); break; - case 0x0A: LD(_state.A, Read(_regBC)); break; - case 0x0B: DEC(_regBC); break; - case 0x0C: INC(_state.C); break; - case 0x0D: DEC(_state.C); break; - case 0x0E: LD(_state.C, ReadCode()); break; - case 0x0F: RRCA(); break; - case 0x10: STOP(); break; - case 0x11: LD(_regDE, ReadCodeWord()); break; - case 0x12: LD_Indirect(_regDE, _state.A); break; - case 0x13: INC(_regDE); break; - case 0x14: INC(_state.D); break; - case 0x15: DEC(_state.D); break; - case 0x16: LD(_state.D, ReadCode()); break; - case 0x17: RLA(); break; - case 0x18: JR(ReadCode()); break; - case 0x19: ADD(_regHL, _regDE); break; - case 0x1A: LD(_state.A, Read(_regDE)); break; - case 0x1B: DEC(_regDE); break; - case 0x1C: INC(_state.E); break; - case 0x1D: DEC(_state.E); break; - case 0x1E: LD(_state.E, ReadCode()); break; - case 0x1F: RRA(); break; - case 0x20: JR((_state.Flags & GbCpuFlags::Zero) == 0, ReadCode()); break; - case 0x21: LD(_regHL, ReadCodeWord()); break; - case 0x22: LD_Indirect(_regHL, _state.A); _regHL.Inc(); break; - case 0x23: INC(_regHL); break; - case 0x24: INC(_state.H); break; - case 0x25: DEC(_state.H); break; - case 0x26: LD(_state.H, ReadCode()); break; - case 0x27: DAA(); break; - case 0x28: JR((_state.Flags & GbCpuFlags::Zero) != 0, ReadCode()); break; - case 0x29: ADD(_regHL, _regHL); break; - case 0x2A: LD(_state.A, Read(_regHL)); _regHL.Inc(); break; - case 0x2B: DEC(_regHL); break; - case 0x2C: INC(_state.L); break; - case 0x2D: DEC(_state.L); break; - case 0x2E: LD(_state.L, ReadCode()); break; - case 0x2F: CPL(); break; - case 0x30: JR((_state.Flags & GbCpuFlags::Carry) == 0, ReadCode()); break; - case 0x31: LD(_state.SP, ReadCodeWord()); break; - case 0x32: LD_Indirect(_regHL, _state.A); _regHL.Dec(); break; - case 0x33: INC_SP(); break; - case 0x34: INC_Indirect(_regHL); break; - case 0x35: DEC_Indirect(_regHL); break; - case 0x36: LD_Indirect(_regHL, ReadCode()); break; - case 0x37: SCF(); break; - case 0x38: JR((_state.Flags & GbCpuFlags::Carry) != 0, ReadCode()); break; - case 0x39: ADD(_regHL, _state.SP); break; - case 0x3A: LD(_state.A, Read(_regHL)); _regHL.Dec(); break; - case 0x3B: DEC_SP(); break; - case 0x3C: INC(_state.A); break; - case 0x3D: DEC(_state.A); break; - case 0x3E: LD(_state.A, ReadCode()); break; - case 0x3F: CCF(); break; - case 0x40: LD(_state.B, _state.B); break; - case 0x41: LD(_state.B, _state.C); break; - case 0x42: LD(_state.B, _state.D); break; - case 0x43: LD(_state.B, _state.E); break; - case 0x44: LD(_state.B, _state.H); break; - case 0x45: LD(_state.B, _state.L); break; - case 0x46: LD(_state.B, Read(_regHL)); break; - case 0x47: LD(_state.B, _state.A); break; - case 0x48: LD(_state.C, _state.B); break; - case 0x49: LD(_state.C, _state.C); break; - case 0x4A: LD(_state.C, _state.D); break; - case 0x4B: LD(_state.C, _state.E); break; - case 0x4C: LD(_state.C, _state.H); break; - case 0x4D: LD(_state.C, _state.L); break; - case 0x4E: LD(_state.C, Read(_regHL)); break; - case 0x4F: LD(_state.C, _state.A); break; - case 0x50: LD(_state.D, _state.B); break; - case 0x51: LD(_state.D, _state.C); break; - case 0x52: LD(_state.D, _state.D); break; - case 0x53: LD(_state.D, _state.E); break; - case 0x54: LD(_state.D, _state.H); break; - case 0x55: LD(_state.D, _state.L); break; - case 0x56: LD(_state.D, Read(_regHL)); break; - case 0x57: LD(_state.D, _state.A); break; - case 0x58: LD(_state.E, _state.B); break; - case 0x59: LD(_state.E, _state.C); break; - case 0x5A: LD(_state.E, _state.D); break; - case 0x5B: LD(_state.E, _state.E); break; - case 0x5C: LD(_state.E, _state.H); break; - case 0x5D: LD(_state.E, _state.L); break; - case 0x5E: LD(_state.E, Read(_regHL)); break; - case 0x5F: LD(_state.E, _state.A); break; - case 0x60: LD(_state.H, _state.B); break; - case 0x61: LD(_state.H, _state.C); break; - case 0x62: LD(_state.H, _state.D); break; - case 0x63: LD(_state.H, _state.E); break; - case 0x64: LD(_state.H, _state.H); break; - case 0x65: LD(_state.H, _state.L); break; - case 0x66: LD(_state.H, Read(_regHL)); break; - case 0x67: LD(_state.H, _state.A); break; - case 0x68: LD(_state.L, _state.B); break; - case 0x69: LD(_state.L, _state.C); break; - case 0x6A: LD(_state.L, _state.D); break; - case 0x6B: LD(_state.L, _state.E); break; - case 0x6C: LD(_state.L, _state.H); break; - case 0x6D: LD(_state.L, _state.L); break; - case 0x6E: LD(_state.L, Read(_regHL)); break; - case 0x6F: LD(_state.L, _state.A); break; - case 0x70: LD_Indirect(_regHL, _state.B); break; - case 0x71: LD_Indirect(_regHL, _state.C); break; - case 0x72: LD_Indirect(_regHL, _state.D); break; - case 0x73: LD_Indirect(_regHL, _state.E); break; - case 0x74: LD_Indirect(_regHL, _state.H); break; - case 0x75: LD_Indirect(_regHL, _state.L); break; - case 0x76: HALT(); break; - case 0x77: LD_Indirect(_regHL, _state.A); break; - case 0x78: LD(_state.A, _state.B); break; - case 0x79: LD(_state.A, _state.C); break; - case 0x7A: LD(_state.A, _state.D); break; - case 0x7B: LD(_state.A, _state.E); break; - case 0x7C: LD(_state.A, _state.H); break; - case 0x7D: LD(_state.A, _state.L); break; - case 0x7E: LD(_state.A, Read(_regHL)); break; - case 0x7F: LD(_state.A, _state.A); break; - case 0x80: ADD(_state.B); break; - case 0x81: ADD(_state.C); break; - case 0x82: ADD(_state.D); break; - case 0x83: ADD(_state.E); break; - case 0x84: ADD(_state.H); break; - case 0x85: ADD(_state.L); break; - case 0x86: ADD(Read(_regHL)); break; - case 0x87: ADD(_state.A); break; - case 0x88: ADC(_state.B); break; - case 0x89: ADC(_state.C); break; - case 0x8A: ADC(_state.D); break; - case 0x8B: ADC(_state.E); break; - case 0x8C: ADC(_state.H); break; - case 0x8D: ADC(_state.L); break; - case 0x8E: ADC(Read(_regHL)); break; - case 0x8F: ADC(_state.A); break; - case 0x90: SUB(_state.B); break; - case 0x91: SUB(_state.C); break; - case 0x92: SUB(_state.D); break; - case 0x93: SUB(_state.E); break; - case 0x94: SUB(_state.H); break; - case 0x95: SUB(_state.L); break; - case 0x96: SUB(Read(_regHL)); break; - case 0x97: SUB(_state.A); break; - case 0x98: SBC(_state.B); break; - case 0x99: SBC(_state.C); break; - case 0x9A: SBC(_state.D); break; - case 0x9B: SBC(_state.E); break; - case 0x9C: SBC(_state.H); break; - case 0x9D: SBC(_state.L); break; - case 0x9E: SBC(Read(_regHL)); break; - case 0x9F: SBC(_state.A); break; - case 0xA0: AND(_state.B); break; - case 0xA1: AND(_state.C); break; - case 0xA2: AND(_state.D); break; - case 0xA3: AND(_state.E); break; - case 0xA4: AND(_state.H); break; - case 0xA5: AND(_state.L); break; - case 0xA6: AND(Read(_regHL)); break; - case 0xA7: AND(_state.A); break; - case 0xA8: XOR(_state.B); break; - case 0xA9: XOR(_state.C); break; - case 0xAA: XOR(_state.D); break; - case 0xAB: XOR(_state.E); break; - case 0xAC: XOR(_state.H); break; - case 0xAD: XOR(_state.L); break; - case 0xAE: XOR(Read(_regHL)); break; - case 0xAF: XOR(_state.A); break; - case 0xB0: OR(_state.B); break; - case 0xB1: OR(_state.C); break; - case 0xB2: OR(_state.D); break; - case 0xB3: OR(_state.E); break; - case 0xB4: OR(_state.H); break; - case 0xB5: OR(_state.L); break; - case 0xB6: OR(Read(_regHL)); break; - case 0xB7: OR(_state.A); break; - case 0xB8: CP(_state.B); break; - case 0xB9: CP(_state.C); break; - case 0xBA: CP(_state.D); break; - case 0xBB: CP(_state.E); break; - case 0xBC: CP(_state.H); break; - case 0xBD: CP(_state.L); break; - case 0xBE: CP(Read(_regHL)); break; - case 0xBF: CP(_state.A); break; - case 0xC0: RET((_state.Flags & GbCpuFlags::Zero) == 0); break; - case 0xC1: POP(_regBC); break; - case 0xC2: JP((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); break; - case 0xC3: JP(ReadCodeWord()); break; - case 0xC4: CALL((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); break; - case 0xC5: PUSH(_regBC); break; - case 0xC6: ADD(ReadCode()); break; - case 0xC7: RST(0x00); break; - case 0xC8: RET((_state.Flags & GbCpuFlags::Zero) != 0); break; - case 0xC9: RET(); break; - case 0xCA: JP((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); break; - case 0xCB: PREFIX(); break; - case 0xCC: CALL((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); break; - case 0xCD: CALL(ReadCodeWord()); break; - case 0xCE: ADC(ReadCode()); break; - case 0xCF: RST(0x08); break; - case 0xD0: RET((_state.Flags & GbCpuFlags::Carry) == 0); break; - case 0xD1: POP(_regDE); break; - case 0xD2: JP((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); break; - case 0xD3: InvalidOp(); break; - case 0xD4: CALL((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); break; - case 0xD5: PUSH(_regDE); break; - case 0xD6: SUB(ReadCode()); break; - case 0xD7: RST(0x10); break; - case 0xD8: RET((_state.Flags & GbCpuFlags::Carry) != 0); break; - case 0xD9: RETI(); break; - case 0xDA: JP((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); break; - case 0xDB: InvalidOp(); break; - case 0xDC: CALL((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); break; - case 0xDD: InvalidOp(); break; - case 0xDE: SBC(ReadCode()); break; - case 0xDF: RST(0x18); break; - case 0xE0: LD_Indirect(0xFF00 | ReadCode(), _state.A); break; - case 0xE1: POP(_regHL); break; - case 0xE2: LD_Indirect(0xFF00 | _state.C, _state.A); break; - case 0xE3: InvalidOp(); break; - case 0xE4: InvalidOp(); break; - case 0xE5: PUSH(_regHL); break; - case 0xE6: AND(ReadCode()); break; - case 0xE7: RST(0x20); break; - case 0xE8: ADD_SP(ReadCode()); break; - case 0xE9: JP_HL(); break; - case 0xEA: LD_Indirect(ReadCodeWord(), _state.A); break; - case 0xEB: InvalidOp(); break; - case 0xEC: InvalidOp(); break; - case 0xED: InvalidOp(); break; - case 0xEE: XOR(ReadCode()); break; - case 0xEF: RST(0x28); break; - case 0xF0: LD(_state.A, Read(0xFF00 | ReadCode())); break; - case 0xF1: POP_AF(); break; - case 0xF2: LD(_state.A, Read(0xFF00 | _state.C)); break; - case 0xF3: DI(); break; - case 0xF4: InvalidOp(); break; - case 0xF5: PUSH(_regAF); break; - case 0xF6: OR(ReadCode()); break; - case 0xF7: RST(0x30); break; - case 0xF8: LD_HL(ReadCode()); break; - case 0xF9: LD(_state.SP, _regHL); IncCycleCount(); break; - case 0xFA: LD(_state.A, Read(ReadCodeWord())); break; - case 0xFB: EI(); break; - case 0xFC: InvalidOp(); break; - case 0xFD: InvalidOp(); break; - case 0xFE: CP(ReadCode()); break; - case 0xFF: RST(0x38); break; + switch (opCode) + { + case 0x00: NOP(); + break; + case 0x01: LD(_regBC, ReadCodeWord()); + break; + case 0x02: LD_Indirect(_regBC, _state.A); + break; + case 0x03: INC(_regBC); + break; + case 0x04: INC(_state.B); + break; + case 0x05: DEC(_state.B); + break; + case 0x06: LD(_state.B, ReadCode()); + break; + case 0x07: RLCA(); + break; + case 0x08: LD_Indirect16(ReadCodeWord(), _state.SP); + break; + case 0x09: ADD(_regHL, _regBC); + break; + case 0x0A: LD(_state.A, Read(_regBC)); + break; + case 0x0B: DEC(_regBC); + break; + case 0x0C: INC(_state.C); + break; + case 0x0D: DEC(_state.C); + break; + case 0x0E: LD(_state.C, ReadCode()); + break; + case 0x0F: RRCA(); + break; + case 0x10: STOP(); + break; + case 0x11: LD(_regDE, ReadCodeWord()); + break; + case 0x12: LD_Indirect(_regDE, _state.A); + break; + case 0x13: INC(_regDE); + break; + case 0x14: INC(_state.D); + break; + case 0x15: DEC(_state.D); + break; + case 0x16: LD(_state.D, ReadCode()); + break; + case 0x17: RLA(); + break; + case 0x18: JR(ReadCode()); + break; + case 0x19: ADD(_regHL, _regDE); + break; + case 0x1A: LD(_state.A, Read(_regDE)); + break; + case 0x1B: DEC(_regDE); + break; + case 0x1C: INC(_state.E); + break; + case 0x1D: DEC(_state.E); + break; + case 0x1E: LD(_state.E, ReadCode()); + break; + case 0x1F: RRA(); + break; + case 0x20: JR((_state.Flags & GbCpuFlags::Zero) == 0, ReadCode()); + break; + case 0x21: LD(_regHL, ReadCodeWord()); + break; + case 0x22: LD_Indirect(_regHL, _state.A); + _regHL.Inc(); + break; + case 0x23: INC(_regHL); + break; + case 0x24: INC(_state.H); + break; + case 0x25: DEC(_state.H); + break; + case 0x26: LD(_state.H, ReadCode()); + break; + case 0x27: DAA(); + break; + case 0x28: JR((_state.Flags & GbCpuFlags::Zero) != 0, ReadCode()); + break; + case 0x29: ADD(_regHL, _regHL); + break; + case 0x2A: LD(_state.A, Read(_regHL)); + _regHL.Inc(); + break; + case 0x2B: DEC(_regHL); + break; + case 0x2C: INC(_state.L); + break; + case 0x2D: DEC(_state.L); + break; + case 0x2E: LD(_state.L, ReadCode()); + break; + case 0x2F: CPL(); + break; + case 0x30: JR((_state.Flags & GbCpuFlags::Carry) == 0, ReadCode()); + break; + case 0x31: LD(_state.SP, ReadCodeWord()); + break; + case 0x32: LD_Indirect(_regHL, _state.A); + _regHL.Dec(); + break; + case 0x33: INC_SP(); + break; + case 0x34: INC_Indirect(_regHL); + break; + case 0x35: DEC_Indirect(_regHL); + break; + case 0x36: LD_Indirect(_regHL, ReadCode()); + break; + case 0x37: SCF(); + break; + case 0x38: JR((_state.Flags & GbCpuFlags::Carry) != 0, ReadCode()); + break; + case 0x39: ADD(_regHL, _state.SP); + break; + case 0x3A: LD(_state.A, Read(_regHL)); + _regHL.Dec(); + break; + case 0x3B: DEC_SP(); + break; + case 0x3C: INC(_state.A); + break; + case 0x3D: DEC(_state.A); + break; + case 0x3E: LD(_state.A, ReadCode()); + break; + case 0x3F: CCF(); + break; + case 0x40: LD(_state.B, _state.B); + break; + case 0x41: LD(_state.B, _state.C); + break; + case 0x42: LD(_state.B, _state.D); + break; + case 0x43: LD(_state.B, _state.E); + break; + case 0x44: LD(_state.B, _state.H); + break; + case 0x45: LD(_state.B, _state.L); + break; + case 0x46: LD(_state.B, Read(_regHL)); + break; + case 0x47: LD(_state.B, _state.A); + break; + case 0x48: LD(_state.C, _state.B); + break; + case 0x49: LD(_state.C, _state.C); + break; + case 0x4A: LD(_state.C, _state.D); + break; + case 0x4B: LD(_state.C, _state.E); + break; + case 0x4C: LD(_state.C, _state.H); + break; + case 0x4D: LD(_state.C, _state.L); + break; + case 0x4E: LD(_state.C, Read(_regHL)); + break; + case 0x4F: LD(_state.C, _state.A); + break; + case 0x50: LD(_state.D, _state.B); + break; + case 0x51: LD(_state.D, _state.C); + break; + case 0x52: LD(_state.D, _state.D); + break; + case 0x53: LD(_state.D, _state.E); + break; + case 0x54: LD(_state.D, _state.H); + break; + case 0x55: LD(_state.D, _state.L); + break; + case 0x56: LD(_state.D, Read(_regHL)); + break; + case 0x57: LD(_state.D, _state.A); + break; + case 0x58: LD(_state.E, _state.B); + break; + case 0x59: LD(_state.E, _state.C); + break; + case 0x5A: LD(_state.E, _state.D); + break; + case 0x5B: LD(_state.E, _state.E); + break; + case 0x5C: LD(_state.E, _state.H); + break; + case 0x5D: LD(_state.E, _state.L); + break; + case 0x5E: LD(_state.E, Read(_regHL)); + break; + case 0x5F: LD(_state.E, _state.A); + break; + case 0x60: LD(_state.H, _state.B); + break; + case 0x61: LD(_state.H, _state.C); + break; + case 0x62: LD(_state.H, _state.D); + break; + case 0x63: LD(_state.H, _state.E); + break; + case 0x64: LD(_state.H, _state.H); + break; + case 0x65: LD(_state.H, _state.L); + break; + case 0x66: LD(_state.H, Read(_regHL)); + break; + case 0x67: LD(_state.H, _state.A); + break; + case 0x68: LD(_state.L, _state.B); + break; + case 0x69: LD(_state.L, _state.C); + break; + case 0x6A: LD(_state.L, _state.D); + break; + case 0x6B: LD(_state.L, _state.E); + break; + case 0x6C: LD(_state.L, _state.H); + break; + case 0x6D: LD(_state.L, _state.L); + break; + case 0x6E: LD(_state.L, Read(_regHL)); + break; + case 0x6F: LD(_state.L, _state.A); + break; + case 0x70: LD_Indirect(_regHL, _state.B); + break; + case 0x71: LD_Indirect(_regHL, _state.C); + break; + case 0x72: LD_Indirect(_regHL, _state.D); + break; + case 0x73: LD_Indirect(_regHL, _state.E); + break; + case 0x74: LD_Indirect(_regHL, _state.H); + break; + case 0x75: LD_Indirect(_regHL, _state.L); + break; + case 0x76: HALT(); + break; + case 0x77: LD_Indirect(_regHL, _state.A); + break; + case 0x78: LD(_state.A, _state.B); + break; + case 0x79: LD(_state.A, _state.C); + break; + case 0x7A: LD(_state.A, _state.D); + break; + case 0x7B: LD(_state.A, _state.E); + break; + case 0x7C: LD(_state.A, _state.H); + break; + case 0x7D: LD(_state.A, _state.L); + break; + case 0x7E: LD(_state.A, Read(_regHL)); + break; + case 0x7F: LD(_state.A, _state.A); + break; + case 0x80: ADD(_state.B); + break; + case 0x81: ADD(_state.C); + break; + case 0x82: ADD(_state.D); + break; + case 0x83: ADD(_state.E); + break; + case 0x84: ADD(_state.H); + break; + case 0x85: ADD(_state.L); + break; + case 0x86: ADD(Read(_regHL)); + break; + case 0x87: ADD(_state.A); + break; + case 0x88: ADC(_state.B); + break; + case 0x89: ADC(_state.C); + break; + case 0x8A: ADC(_state.D); + break; + case 0x8B: ADC(_state.E); + break; + case 0x8C: ADC(_state.H); + break; + case 0x8D: ADC(_state.L); + break; + case 0x8E: ADC(Read(_regHL)); + break; + case 0x8F: ADC(_state.A); + break; + case 0x90: SUB(_state.B); + break; + case 0x91: SUB(_state.C); + break; + case 0x92: SUB(_state.D); + break; + case 0x93: SUB(_state.E); + break; + case 0x94: SUB(_state.H); + break; + case 0x95: SUB(_state.L); + break; + case 0x96: SUB(Read(_regHL)); + break; + case 0x97: SUB(_state.A); + break; + case 0x98: SBC(_state.B); + break; + case 0x99: SBC(_state.C); + break; + case 0x9A: SBC(_state.D); + break; + case 0x9B: SBC(_state.E); + break; + case 0x9C: SBC(_state.H); + break; + case 0x9D: SBC(_state.L); + break; + case 0x9E: SBC(Read(_regHL)); + break; + case 0x9F: SBC(_state.A); + break; + case 0xA0: AND(_state.B); + break; + case 0xA1: AND(_state.C); + break; + case 0xA2: AND(_state.D); + break; + case 0xA3: AND(_state.E); + break; + case 0xA4: AND(_state.H); + break; + case 0xA5: AND(_state.L); + break; + case 0xA6: AND(Read(_regHL)); + break; + case 0xA7: AND(_state.A); + break; + case 0xA8: XOR(_state.B); + break; + case 0xA9: XOR(_state.C); + break; + case 0xAA: XOR(_state.D); + break; + case 0xAB: XOR(_state.E); + break; + case 0xAC: XOR(_state.H); + break; + case 0xAD: XOR(_state.L); + break; + case 0xAE: XOR(Read(_regHL)); + break; + case 0xAF: XOR(_state.A); + break; + case 0xB0: OR(_state.B); + break; + case 0xB1: OR(_state.C); + break; + case 0xB2: OR(_state.D); + break; + case 0xB3: OR(_state.E); + break; + case 0xB4: OR(_state.H); + break; + case 0xB5: OR(_state.L); + break; + case 0xB6: OR(Read(_regHL)); + break; + case 0xB7: OR(_state.A); + break; + case 0xB8: CP(_state.B); + break; + case 0xB9: CP(_state.C); + break; + case 0xBA: CP(_state.D); + break; + case 0xBB: CP(_state.E); + break; + case 0xBC: CP(_state.H); + break; + case 0xBD: CP(_state.L); + break; + case 0xBE: CP(Read(_regHL)); + break; + case 0xBF: CP(_state.A); + break; + case 0xC0: RET((_state.Flags & GbCpuFlags::Zero) == 0); + break; + case 0xC1: POP(_regBC); + break; + case 0xC2: JP((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); + break; + case 0xC3: JP(ReadCodeWord()); + break; + case 0xC4: CALL((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); + break; + case 0xC5: PUSH(_regBC); + break; + case 0xC6: ADD(ReadCode()); + break; + case 0xC7: RST(0x00); + break; + case 0xC8: RET((_state.Flags & GbCpuFlags::Zero) != 0); + break; + case 0xC9: RET(); + break; + case 0xCA: JP((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); + break; + case 0xCB: PREFIX(); + break; + case 0xCC: CALL((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); + break; + case 0xCD: CALL(ReadCodeWord()); + break; + case 0xCE: ADC(ReadCode()); + break; + case 0xCF: RST(0x08); + break; + case 0xD0: RET((_state.Flags & GbCpuFlags::Carry) == 0); + break; + case 0xD1: POP(_regDE); + break; + case 0xD2: JP((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); + break; + case 0xD3: InvalidOp(); + break; + case 0xD4: CALL((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); + break; + case 0xD5: PUSH(_regDE); + break; + case 0xD6: SUB(ReadCode()); + break; + case 0xD7: RST(0x10); + break; + case 0xD8: RET((_state.Flags & GbCpuFlags::Carry) != 0); + break; + case 0xD9: RETI(); + break; + case 0xDA: JP((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); + break; + case 0xDB: InvalidOp(); + break; + case 0xDC: CALL((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); + break; + case 0xDD: InvalidOp(); + break; + case 0xDE: SBC(ReadCode()); + break; + case 0xDF: RST(0x18); + break; + case 0xE0: LD_Indirect(0xFF00 | ReadCode(), _state.A); + break; + case 0xE1: POP(_regHL); + break; + case 0xE2: LD_Indirect(0xFF00 | _state.C, _state.A); + break; + case 0xE3: InvalidOp(); + break; + case 0xE4: InvalidOp(); + break; + case 0xE5: PUSH(_regHL); + break; + case 0xE6: AND(ReadCode()); + break; + case 0xE7: RST(0x20); + break; + case 0xE8: ADD_SP(ReadCode()); + break; + case 0xE9: JP_HL(); + break; + case 0xEA: LD_Indirect(ReadCodeWord(), _state.A); + break; + case 0xEB: InvalidOp(); + break; + case 0xEC: InvalidOp(); + break; + case 0xED: InvalidOp(); + break; + case 0xEE: XOR(ReadCode()); + break; + case 0xEF: RST(0x28); + break; + case 0xF0: LD(_state.A, Read(0xFF00 | ReadCode())); + break; + case 0xF1: POP_AF(); + break; + case 0xF2: LD(_state.A, Read(0xFF00 | _state.C)); + break; + case 0xF3: DI(); + break; + case 0xF4: InvalidOp(); + break; + case 0xF5: PUSH(_regAF); + break; + case 0xF6: OR(ReadCode()); + break; + case 0xF7: RST(0x30); + break; + case 0xF8: LD_HL(ReadCode()); + break; + case 0xF9: LD(_state.SP, _regHL); + IncCycleCount(); + break; + case 0xFA: LD(_state.A, Read(ReadCodeWord())); + break; + case 0xFB: EI(); + break; + case 0xFC: InvalidOp(); + break; + case 0xFD: InvalidOp(); + break; + case 0xFE: CP(ReadCode()); + break; + case 0xFF: RST(0x38); + break; } } @@ -412,9 +685,12 @@ void GbCpu::ClearFlag(uint8_t flag) void GbCpu::SetFlagState(uint8_t flag, bool state) { - if(state) { + if (state) + { SetFlag(flag); - } else { + } + else + { ClearFlag(flag); } } @@ -704,7 +980,6 @@ void GbCpu::CP(uint8_t value) void GbCpu::NOP() { - } void GbCpu::InvalidOp() @@ -718,18 +993,24 @@ void GbCpu::InvalidOp() void GbCpu::STOP() { - if(_gameboy->IsCgb() && _memoryManager->GetState().CgbSwitchSpeedRequest) { + if (_gameboy->IsCgb() && _memoryManager->GetState().CgbSwitchSpeedRequest) + { _memoryManager->ToggleSpeed(); - } else { + } + else + { _state.Halted = true; } } void GbCpu::HALT() { - if(_state.IME || _memoryManager->ProcessIrqRequests() == 0) { + if (_state.IME || _memoryManager->ProcessIrqRequests() == 0) + { _state.Halted = true; - } else { + } + else + { //HALT bug, execution continues, but PC isn't incremented for the first byte HalfCycle(); uint8_t opCode = _memoryManager->Read(_state.PC); @@ -928,7 +1209,7 @@ void GbCpu::SWAP_Indirect(uint16_t addr) Write(addr, val); } -template +template void GbCpu::BIT(uint8_t src) { SetFlagState(GbCpuFlags::Zero, (src & (1 << bit)) == 0); @@ -936,13 +1217,13 @@ void GbCpu::BIT(uint8_t src) SetFlag(GbCpuFlags::HalfCarry); } -template +template void GbCpu::RES(uint8_t& dst) { dst &= ~(1 << bit); } -template +template void GbCpu::RES_Indirect(uint16_t addr) { uint8_t val = Read(addr); @@ -950,13 +1231,13 @@ void GbCpu::RES_Indirect(uint16_t addr) Write(addr, val); } -template +template void GbCpu::SET(uint8_t& dst) { dst |= (1 << bit); } -template +template void GbCpu::SET_Indirect(uint16_t addr) { uint8_t val = Read(addr); @@ -967,19 +1248,26 @@ void GbCpu::SET_Indirect(uint16_t addr) // daa 27 4 z-0x decimal adjust akku void GbCpu::DAA() { - if(CheckFlag(GbCpuFlags::AddSub)) { - if(CheckFlag(GbCpuFlags::Carry)) { + if (CheckFlag(GbCpuFlags::AddSub)) + { + if (CheckFlag(GbCpuFlags::Carry)) + { _state.A -= 0x60; } - if(CheckFlag(GbCpuFlags::HalfCarry)) { + if (CheckFlag(GbCpuFlags::HalfCarry)) + { _state.A -= 0x06; } - } else { - if(CheckFlag(GbCpuFlags::Carry) || _state.A > 0x99) { + } + else + { + if (CheckFlag(GbCpuFlags::Carry) || _state.A > 0x99) + { _state.A += 0x60; SetFlag(GbCpuFlags::Carry); } - if(CheckFlag(GbCpuFlags::HalfCarry) || (_state.A & 0x0F) > 0x09) { + if (CheckFlag(GbCpuFlags::HalfCarry) || (_state.A & 0x0F) > 0x09) + { _state.A += 0x6; } } @@ -1004,7 +1292,8 @@ void GbCpu::JP_HL() //jp f,nn xx nn nn 16;12 ---- conditional jump if nz,z,nc,c void GbCpu::JP(bool condition, uint16_t dstAddr) { - if(condition) { + if (condition) + { _state.PC = dstAddr; IncCycleCount(); } @@ -1020,7 +1309,8 @@ void GbCpu::JR(int8_t offset) //jr f,PC+dd xx dd 12;8 ---- conditional relative jump if nz,z,nc,c void GbCpu::JR(bool condition, int8_t offset) { - if(condition) { + if (condition) + { _state.PC += offset; IncCycleCount(); } @@ -1037,7 +1327,8 @@ void GbCpu::CALL(uint16_t dstAddr) //call f,nn xx nn nn 24;12 ---- conditional call if nz,z,nc,c void GbCpu::CALL(bool condition, uint16_t dstAddr) { - if(condition) { + if (condition) + { IncCycleCount(); PushWord(_state.PC); _state.PC = dstAddr; @@ -1055,7 +1346,8 @@ void GbCpu::RET() void GbCpu::RET(bool condition) { IncCycleCount(); - if(condition) { + if (condition) + { _state.PC = PopWord(); IncCycleCount(); } @@ -1121,263 +1413,520 @@ void GbCpu::DI() void GbCpu::PREFIX() { - switch(ReadCode()) { - case 0x00: RLC(_state.B); break; - case 0x01: RLC(_state.C); break; - case 0x02: RLC(_state.D); break; - case 0x03: RLC(_state.E); break; - case 0x04: RLC(_state.H); break; - case 0x05: RLC(_state.L); break; - case 0x06: RLC_Indirect(_regHL); break; - case 0x07: RLC(_state.A); break; - case 0x08: RRC(_state.B); break; - case 0x09: RRC(_state.C); break; - case 0x0A: RRC(_state.D); break; - case 0x0B: RRC(_state.E); break; - case 0x0C: RRC(_state.H); break; - case 0x0D: RRC(_state.L); break; - case 0x0E: RRC_Indirect(_regHL); break; - case 0x0F: RRC(_state.A); break; - case 0x10: RL(_state.B); break; - case 0x11: RL(_state.C); break; - case 0x12: RL(_state.D); break; - case 0x13: RL(_state.E); break; - case 0x14: RL(_state.H); break; - case 0x15: RL(_state.L); break; - case 0x16: RL_Indirect(_regHL); break; - case 0x17: RL(_state.A); break; - case 0x18: RR(_state.B); break; - case 0x19: RR(_state.C); break; - case 0x1A: RR(_state.D); break; - case 0x1B: RR(_state.E); break; - case 0x1C: RR(_state.H); break; - case 0x1D: RR(_state.L); break; - case 0x1E: RR_Indirect(_regHL); break; - case 0x1F: RR(_state.A); break; - case 0x20: SLA(_state.B); break; - case 0x21: SLA(_state.C); break; - case 0x22: SLA(_state.D); break; - case 0x23: SLA(_state.E); break; - case 0x24: SLA(_state.H); break; - case 0x25: SLA(_state.L); break; - case 0x26: SLA_Indirect(_regHL); break; - case 0x27: SLA(_state.A); break; - case 0x28: SRA(_state.B); break; - case 0x29: SRA(_state.C); break; - case 0x2A: SRA(_state.D); break; - case 0x2B: SRA(_state.E); break; - case 0x2C: SRA(_state.H); break; - case 0x2D: SRA(_state.L); break; - case 0x2E: SRA_Indirect(_regHL); break; - case 0x2F: SRA(_state.A); break; - case 0x30: SWAP(_state.B); break; - case 0x31: SWAP(_state.C); break; - case 0x32: SWAP(_state.D); break; - case 0x33: SWAP(_state.E); break; - case 0x34: SWAP(_state.H); break; - case 0x35: SWAP(_state.L); break; - case 0x36: SWAP_Indirect(_regHL); break; - case 0x37: SWAP(_state.A); break; - case 0x38: SRL(_state.B); break; - case 0x39: SRL(_state.C); break; - case 0x3A: SRL(_state.D); break; - case 0x3B: SRL(_state.E); break; - case 0x3C: SRL(_state.H); break; - case 0x3D: SRL(_state.L); break; - case 0x3E: SRL_Indirect(_regHL); break; - case 0x3F: SRL(_state.A); break; - case 0x40: BIT<0>(_state.B); break; - case 0x41: BIT<0>(_state.C); break; - case 0x42: BIT<0>(_state.D); break; - case 0x43: BIT<0>(_state.E); break; - case 0x44: BIT<0>(_state.H); break; - case 0x45: BIT<0>(_state.L); break; - case 0x46: BIT<0>(Read(_regHL)); break; - case 0x47: BIT<0>(_state.A); break; - case 0x48: BIT<1>(_state.B); break; - case 0x49: BIT<1>(_state.C); break; - case 0x4A: BIT<1>(_state.D); break; - case 0x4B: BIT<1>(_state.E); break; - case 0x4C: BIT<1>(_state.H); break; - case 0x4D: BIT<1>(_state.L); break; - case 0x4E: BIT<1>(Read(_regHL)); break; - case 0x4F: BIT<1>(_state.A); break; - case 0x50: BIT<2>(_state.B); break; - case 0x51: BIT<2>(_state.C); break; - case 0x52: BIT<2>(_state.D); break; - case 0x53: BIT<2>(_state.E); break; - case 0x54: BIT<2>(_state.H); break; - case 0x55: BIT<2>(_state.L); break; - case 0x56: BIT<2>(Read(_regHL)); break; - case 0x57: BIT<2>(_state.A); break; - case 0x58: BIT<3>(_state.B); break; - case 0x59: BIT<3>(_state.C); break; - case 0x5A: BIT<3>(_state.D); break; - case 0x5B: BIT<3>(_state.E); break; - case 0x5C: BIT<3>(_state.H); break; - case 0x5D: BIT<3>(_state.L); break; - case 0x5E: BIT<3>(Read(_regHL)); break; - case 0x5F: BIT<3>(_state.A); break; - case 0x60: BIT<4>(_state.B); break; - case 0x61: BIT<4>(_state.C); break; - case 0x62: BIT<4>(_state.D); break; - case 0x63: BIT<4>(_state.E); break; - case 0x64: BIT<4>(_state.H); break; - case 0x65: BIT<4>(_state.L); break; - case 0x66: BIT<4>(Read(_regHL)); break; - case 0x67: BIT<4>(_state.A); break; - case 0x68: BIT<5>(_state.B); break; - case 0x69: BIT<5>(_state.C); break; - case 0x6A: BIT<5>(_state.D); break; - case 0x6B: BIT<5>(_state.E); break; - case 0x6C: BIT<5>(_state.H); break; - case 0x6D: BIT<5>(_state.L); break; - case 0x6E: BIT<5>(Read(_regHL)); break; - case 0x6F: BIT<5>(_state.A); break; - case 0x70: BIT<6>(_state.B); break; - case 0x71: BIT<6>(_state.C); break; - case 0x72: BIT<6>(_state.D); break; - case 0x73: BIT<6>(_state.E); break; - case 0x74: BIT<6>(_state.H); break; - case 0x75: BIT<6>(_state.L); break; - case 0x76: BIT<6>(Read(_regHL)); break; - case 0x77: BIT<6>(_state.A); break; - case 0x78: BIT<7>(_state.B); break; - case 0x79: BIT<7>(_state.C); break; - case 0x7A: BIT<7>(_state.D); break; - case 0x7B: BIT<7>(_state.E); break; - case 0x7C: BIT<7>(_state.H); break; - case 0x7D: BIT<7>(_state.L); break; - case 0x7E: BIT<7>(Read(_regHL)); break; - case 0x7F: BIT<7>(_state.A); break; - case 0x80: RES<0>(_state.B); break; - case 0x81: RES<0>(_state.C); break; - case 0x82: RES<0>(_state.D); break; - case 0x83: RES<0>(_state.E); break; - case 0x84: RES<0>(_state.H); break; - case 0x85: RES<0>(_state.L); break; - case 0x86: RES_Indirect<0>(_regHL); break; - case 0x87: RES<0>(_state.A); break; - case 0x88: RES<1>(_state.B); break; - case 0x89: RES<1>(_state.C); break; - case 0x8A: RES<1>(_state.D); break; - case 0x8B: RES<1>(_state.E); break; - case 0x8C: RES<1>(_state.H); break; - case 0x8D: RES<1>(_state.L); break; - case 0x8E: RES_Indirect<1>(_regHL); break; - case 0x8F: RES<1>(_state.A); break; - case 0x90: RES<2>(_state.B); break; - case 0x91: RES<2>(_state.C); break; - case 0x92: RES<2>(_state.D); break; - case 0x93: RES<2>(_state.E); break; - case 0x94: RES<2>(_state.H); break; - case 0x95: RES<2>(_state.L); break; - case 0x96: RES_Indirect<2>(_regHL); break; - case 0x97: RES<2>(_state.A); break; - case 0x98: RES<3>(_state.B); break; - case 0x99: RES<3>(_state.C); break; - case 0x9A: RES<3>(_state.D); break; - case 0x9B: RES<3>(_state.E); break; - case 0x9C: RES<3>(_state.H); break; - case 0x9D: RES<3>(_state.L); break; - case 0x9E: RES_Indirect<3>(_regHL); break; - case 0x9F: RES<3>(_state.A); break; - case 0xA0: RES<4>(_state.B); break; - case 0xA1: RES<4>(_state.C); break; - case 0xA2: RES<4>(_state.D); break; - case 0xA3: RES<4>(_state.E); break; - case 0xA4: RES<4>(_state.H); break; - case 0xA5: RES<4>(_state.L); break; - case 0xA6: RES_Indirect<4>(_regHL); break; - case 0xA7: RES<4>(_state.A); break; - case 0xA8: RES<5>(_state.B); break; - case 0xA9: RES<5>(_state.C); break; - case 0xAA: RES<5>(_state.D); break; - case 0xAB: RES<5>(_state.E); break; - case 0xAC: RES<5>(_state.H); break; - case 0xAD: RES<5>(_state.L); break; - case 0xAE: RES_Indirect<5>(_regHL); break; - case 0xAF: RES<5>(_state.A); break; - case 0xB0: RES<6>(_state.B); break; - case 0xB1: RES<6>(_state.C); break; - case 0xB2: RES<6>(_state.D); break; - case 0xB3: RES<6>(_state.E); break; - case 0xB4: RES<6>(_state.H); break; - case 0xB5: RES<6>(_state.L); break; - case 0xB6: RES_Indirect<6>(_regHL); break; - case 0xB7: RES<6>(_state.A); break; - case 0xB8: RES<7>(_state.B); break; - case 0xB9: RES<7>(_state.C); break; - case 0xBA: RES<7>(_state.D); break; - case 0xBB: RES<7>(_state.E); break; - case 0xBC: RES<7>(_state.H); break; - case 0xBD: RES<7>(_state.L); break; - case 0xBE: RES_Indirect<7>(_regHL); break; - case 0xBF: RES<7>(_state.A); break; - case 0xC0: SET<0>(_state.B); break; - case 0xC1: SET<0>(_state.C); break; - case 0xC2: SET<0>(_state.D); break; - case 0xC3: SET<0>(_state.E); break; - case 0xC4: SET<0>(_state.H); break; - case 0xC5: SET<0>(_state.L); break; - case 0xC6: SET_Indirect<0>(_regHL); break; - case 0xC7: SET<0>(_state.A); break; - case 0xC8: SET<1>(_state.B); break; - case 0xC9: SET<1>(_state.C); break; - case 0xCA: SET<1>(_state.D); break; - case 0xCB: SET<1>(_state.E); break; - case 0xCC: SET<1>(_state.H); break; - case 0xCD: SET<1>(_state.L); break; - case 0xCE: SET_Indirect<1>(_regHL); break; - case 0xCF: SET<1>(_state.A); break; - case 0xD0: SET<2>(_state.B); break; - case 0xD1: SET<2>(_state.C); break; - case 0xD2: SET<2>(_state.D); break; - case 0xD3: SET<2>(_state.E); break; - case 0xD4: SET<2>(_state.H); break; - case 0xD5: SET<2>(_state.L); break; - case 0xD6: SET_Indirect<2>(_regHL); break; - case 0xD7: SET<2>(_state.A); break; - case 0xD8: SET<3>(_state.B); break; - case 0xD9: SET<3>(_state.C); break; - case 0xDA: SET<3>(_state.D); break; - case 0xDB: SET<3>(_state.E); break; - case 0xDC: SET<3>(_state.H); break; - case 0xDD: SET<3>(_state.L); break; - case 0xDE: SET_Indirect<3>(_regHL); break; - case 0xDF: SET<3>(_state.A); break; - case 0xE0: SET<4>(_state.B); break; - case 0xE1: SET<4>(_state.C); break; - case 0xE2: SET<4>(_state.D); break; - case 0xE3: SET<4>(_state.E); break; - case 0xE4: SET<4>(_state.H); break; - case 0xE5: SET<4>(_state.L); break; - case 0xE6: SET_Indirect<4>(_regHL); break; - case 0xE7: SET<4>(_state.A); break; - case 0xE8: SET<5>(_state.B); break; - case 0xE9: SET<5>(_state.C); break; - case 0xEA: SET<5>(_state.D); break; - case 0xEB: SET<5>(_state.E); break; - case 0xEC: SET<5>(_state.H); break; - case 0xED: SET<5>(_state.L); break; - case 0xEE: SET_Indirect<5>(_regHL); break; - case 0xEF: SET<5>(_state.A); break; - case 0xF0: SET<6>(_state.B); break; - case 0xF1: SET<6>(_state.C); break; - case 0xF2: SET<6>(_state.D); break; - case 0xF3: SET<6>(_state.E); break; - case 0xF4: SET<6>(_state.H); break; - case 0xF5: SET<6>(_state.L); break; - case 0xF6: SET_Indirect<6>(_regHL); break; - case 0xF7: SET<6>(_state.A); break; - case 0xF8: SET<7>(_state.B); break; - case 0xF9: SET<7>(_state.C); break; - case 0xFA: SET<7>(_state.D); break; - case 0xFB: SET<7>(_state.E); break; - case 0xFC: SET<7>(_state.H); break; - case 0xFD: SET<7>(_state.L); break; - case 0xFE: SET_Indirect<7>(_regHL); break; - case 0xFF: SET<7>(_state.A); break; + switch (ReadCode()) + { + case 0x00: RLC(_state.B); + break; + case 0x01: RLC(_state.C); + break; + case 0x02: RLC(_state.D); + break; + case 0x03: RLC(_state.E); + break; + case 0x04: RLC(_state.H); + break; + case 0x05: RLC(_state.L); + break; + case 0x06: RLC_Indirect(_regHL); + break; + case 0x07: RLC(_state.A); + break; + case 0x08: RRC(_state.B); + break; + case 0x09: RRC(_state.C); + break; + case 0x0A: RRC(_state.D); + break; + case 0x0B: RRC(_state.E); + break; + case 0x0C: RRC(_state.H); + break; + case 0x0D: RRC(_state.L); + break; + case 0x0E: RRC_Indirect(_regHL); + break; + case 0x0F: RRC(_state.A); + break; + case 0x10: RL(_state.B); + break; + case 0x11: RL(_state.C); + break; + case 0x12: RL(_state.D); + break; + case 0x13: RL(_state.E); + break; + case 0x14: RL(_state.H); + break; + case 0x15: RL(_state.L); + break; + case 0x16: RL_Indirect(_regHL); + break; + case 0x17: RL(_state.A); + break; + case 0x18: RR(_state.B); + break; + case 0x19: RR(_state.C); + break; + case 0x1A: RR(_state.D); + break; + case 0x1B: RR(_state.E); + break; + case 0x1C: RR(_state.H); + break; + case 0x1D: RR(_state.L); + break; + case 0x1E: RR_Indirect(_regHL); + break; + case 0x1F: RR(_state.A); + break; + case 0x20: SLA(_state.B); + break; + case 0x21: SLA(_state.C); + break; + case 0x22: SLA(_state.D); + break; + case 0x23: SLA(_state.E); + break; + case 0x24: SLA(_state.H); + break; + case 0x25: SLA(_state.L); + break; + case 0x26: SLA_Indirect(_regHL); + break; + case 0x27: SLA(_state.A); + break; + case 0x28: SRA(_state.B); + break; + case 0x29: SRA(_state.C); + break; + case 0x2A: SRA(_state.D); + break; + case 0x2B: SRA(_state.E); + break; + case 0x2C: SRA(_state.H); + break; + case 0x2D: SRA(_state.L); + break; + case 0x2E: SRA_Indirect(_regHL); + break; + case 0x2F: SRA(_state.A); + break; + case 0x30: SWAP(_state.B); + break; + case 0x31: SWAP(_state.C); + break; + case 0x32: SWAP(_state.D); + break; + case 0x33: SWAP(_state.E); + break; + case 0x34: SWAP(_state.H); + break; + case 0x35: SWAP(_state.L); + break; + case 0x36: SWAP_Indirect(_regHL); + break; + case 0x37: SWAP(_state.A); + break; + case 0x38: SRL(_state.B); + break; + case 0x39: SRL(_state.C); + break; + case 0x3A: SRL(_state.D); + break; + case 0x3B: SRL(_state.E); + break; + case 0x3C: SRL(_state.H); + break; + case 0x3D: SRL(_state.L); + break; + case 0x3E: SRL_Indirect(_regHL); + break; + case 0x3F: SRL(_state.A); + break; + case 0x40: BIT<0>(_state.B); + break; + case 0x41: BIT<0>(_state.C); + break; + case 0x42: BIT<0>(_state.D); + break; + case 0x43: BIT<0>(_state.E); + break; + case 0x44: BIT<0>(_state.H); + break; + case 0x45: BIT<0>(_state.L); + break; + case 0x46: BIT<0>(Read(_regHL)); + break; + case 0x47: BIT<0>(_state.A); + break; + case 0x48: BIT<1>(_state.B); + break; + case 0x49: BIT<1>(_state.C); + break; + case 0x4A: BIT<1>(_state.D); + break; + case 0x4B: BIT<1>(_state.E); + break; + case 0x4C: BIT<1>(_state.H); + break; + case 0x4D: BIT<1>(_state.L); + break; + case 0x4E: BIT<1>(Read(_regHL)); + break; + case 0x4F: BIT<1>(_state.A); + break; + case 0x50: BIT<2>(_state.B); + break; + case 0x51: BIT<2>(_state.C); + break; + case 0x52: BIT<2>(_state.D); + break; + case 0x53: BIT<2>(_state.E); + break; + case 0x54: BIT<2>(_state.H); + break; + case 0x55: BIT<2>(_state.L); + break; + case 0x56: BIT<2>(Read(_regHL)); + break; + case 0x57: BIT<2>(_state.A); + break; + case 0x58: BIT<3>(_state.B); + break; + case 0x59: BIT<3>(_state.C); + break; + case 0x5A: BIT<3>(_state.D); + break; + case 0x5B: BIT<3>(_state.E); + break; + case 0x5C: BIT<3>(_state.H); + break; + case 0x5D: BIT<3>(_state.L); + break; + case 0x5E: BIT<3>(Read(_regHL)); + break; + case 0x5F: BIT<3>(_state.A); + break; + case 0x60: BIT<4>(_state.B); + break; + case 0x61: BIT<4>(_state.C); + break; + case 0x62: BIT<4>(_state.D); + break; + case 0x63: BIT<4>(_state.E); + break; + case 0x64: BIT<4>(_state.H); + break; + case 0x65: BIT<4>(_state.L); + break; + case 0x66: BIT<4>(Read(_regHL)); + break; + case 0x67: BIT<4>(_state.A); + break; + case 0x68: BIT<5>(_state.B); + break; + case 0x69: BIT<5>(_state.C); + break; + case 0x6A: BIT<5>(_state.D); + break; + case 0x6B: BIT<5>(_state.E); + break; + case 0x6C: BIT<5>(_state.H); + break; + case 0x6D: BIT<5>(_state.L); + break; + case 0x6E: BIT<5>(Read(_regHL)); + break; + case 0x6F: BIT<5>(_state.A); + break; + case 0x70: BIT<6>(_state.B); + break; + case 0x71: BIT<6>(_state.C); + break; + case 0x72: BIT<6>(_state.D); + break; + case 0x73: BIT<6>(_state.E); + break; + case 0x74: BIT<6>(_state.H); + break; + case 0x75: BIT<6>(_state.L); + break; + case 0x76: BIT<6>(Read(_regHL)); + break; + case 0x77: BIT<6>(_state.A); + break; + case 0x78: BIT<7>(_state.B); + break; + case 0x79: BIT<7>(_state.C); + break; + case 0x7A: BIT<7>(_state.D); + break; + case 0x7B: BIT<7>(_state.E); + break; + case 0x7C: BIT<7>(_state.H); + break; + case 0x7D: BIT<7>(_state.L); + break; + case 0x7E: BIT<7>(Read(_regHL)); + break; + case 0x7F: BIT<7>(_state.A); + break; + case 0x80: RES<0>(_state.B); + break; + case 0x81: RES<0>(_state.C); + break; + case 0x82: RES<0>(_state.D); + break; + case 0x83: RES<0>(_state.E); + break; + case 0x84: RES<0>(_state.H); + break; + case 0x85: RES<0>(_state.L); + break; + case 0x86: RES_Indirect<0>(_regHL); + break; + case 0x87: RES<0>(_state.A); + break; + case 0x88: RES<1>(_state.B); + break; + case 0x89: RES<1>(_state.C); + break; + case 0x8A: RES<1>(_state.D); + break; + case 0x8B: RES<1>(_state.E); + break; + case 0x8C: RES<1>(_state.H); + break; + case 0x8D: RES<1>(_state.L); + break; + case 0x8E: RES_Indirect<1>(_regHL); + break; + case 0x8F: RES<1>(_state.A); + break; + case 0x90: RES<2>(_state.B); + break; + case 0x91: RES<2>(_state.C); + break; + case 0x92: RES<2>(_state.D); + break; + case 0x93: RES<2>(_state.E); + break; + case 0x94: RES<2>(_state.H); + break; + case 0x95: RES<2>(_state.L); + break; + case 0x96: RES_Indirect<2>(_regHL); + break; + case 0x97: RES<2>(_state.A); + break; + case 0x98: RES<3>(_state.B); + break; + case 0x99: RES<3>(_state.C); + break; + case 0x9A: RES<3>(_state.D); + break; + case 0x9B: RES<3>(_state.E); + break; + case 0x9C: RES<3>(_state.H); + break; + case 0x9D: RES<3>(_state.L); + break; + case 0x9E: RES_Indirect<3>(_regHL); + break; + case 0x9F: RES<3>(_state.A); + break; + case 0xA0: RES<4>(_state.B); + break; + case 0xA1: RES<4>(_state.C); + break; + case 0xA2: RES<4>(_state.D); + break; + case 0xA3: RES<4>(_state.E); + break; + case 0xA4: RES<4>(_state.H); + break; + case 0xA5: RES<4>(_state.L); + break; + case 0xA6: RES_Indirect<4>(_regHL); + break; + case 0xA7: RES<4>(_state.A); + break; + case 0xA8: RES<5>(_state.B); + break; + case 0xA9: RES<5>(_state.C); + break; + case 0xAA: RES<5>(_state.D); + break; + case 0xAB: RES<5>(_state.E); + break; + case 0xAC: RES<5>(_state.H); + break; + case 0xAD: RES<5>(_state.L); + break; + case 0xAE: RES_Indirect<5>(_regHL); + break; + case 0xAF: RES<5>(_state.A); + break; + case 0xB0: RES<6>(_state.B); + break; + case 0xB1: RES<6>(_state.C); + break; + case 0xB2: RES<6>(_state.D); + break; + case 0xB3: RES<6>(_state.E); + break; + case 0xB4: RES<6>(_state.H); + break; + case 0xB5: RES<6>(_state.L); + break; + case 0xB6: RES_Indirect<6>(_regHL); + break; + case 0xB7: RES<6>(_state.A); + break; + case 0xB8: RES<7>(_state.B); + break; + case 0xB9: RES<7>(_state.C); + break; + case 0xBA: RES<7>(_state.D); + break; + case 0xBB: RES<7>(_state.E); + break; + case 0xBC: RES<7>(_state.H); + break; + case 0xBD: RES<7>(_state.L); + break; + case 0xBE: RES_Indirect<7>(_regHL); + break; + case 0xBF: RES<7>(_state.A); + break; + case 0xC0: SET<0>(_state.B); + break; + case 0xC1: SET<0>(_state.C); + break; + case 0xC2: SET<0>(_state.D); + break; + case 0xC3: SET<0>(_state.E); + break; + case 0xC4: SET<0>(_state.H); + break; + case 0xC5: SET<0>(_state.L); + break; + case 0xC6: SET_Indirect<0>(_regHL); + break; + case 0xC7: SET<0>(_state.A); + break; + case 0xC8: SET<1>(_state.B); + break; + case 0xC9: SET<1>(_state.C); + break; + case 0xCA: SET<1>(_state.D); + break; + case 0xCB: SET<1>(_state.E); + break; + case 0xCC: SET<1>(_state.H); + break; + case 0xCD: SET<1>(_state.L); + break; + case 0xCE: SET_Indirect<1>(_regHL); + break; + case 0xCF: SET<1>(_state.A); + break; + case 0xD0: SET<2>(_state.B); + break; + case 0xD1: SET<2>(_state.C); + break; + case 0xD2: SET<2>(_state.D); + break; + case 0xD3: SET<2>(_state.E); + break; + case 0xD4: SET<2>(_state.H); + break; + case 0xD5: SET<2>(_state.L); + break; + case 0xD6: SET_Indirect<2>(_regHL); + break; + case 0xD7: SET<2>(_state.A); + break; + case 0xD8: SET<3>(_state.B); + break; + case 0xD9: SET<3>(_state.C); + break; + case 0xDA: SET<3>(_state.D); + break; + case 0xDB: SET<3>(_state.E); + break; + case 0xDC: SET<3>(_state.H); + break; + case 0xDD: SET<3>(_state.L); + break; + case 0xDE: SET_Indirect<3>(_regHL); + break; + case 0xDF: SET<3>(_state.A); + break; + case 0xE0: SET<4>(_state.B); + break; + case 0xE1: SET<4>(_state.C); + break; + case 0xE2: SET<4>(_state.D); + break; + case 0xE3: SET<4>(_state.E); + break; + case 0xE4: SET<4>(_state.H); + break; + case 0xE5: SET<4>(_state.L); + break; + case 0xE6: SET_Indirect<4>(_regHL); + break; + case 0xE7: SET<4>(_state.A); + break; + case 0xE8: SET<5>(_state.B); + break; + case 0xE9: SET<5>(_state.C); + break; + case 0xEA: SET<5>(_state.D); + break; + case 0xEB: SET<5>(_state.E); + break; + case 0xEC: SET<5>(_state.H); + break; + case 0xED: SET<5>(_state.L); + break; + case 0xEE: SET_Indirect<5>(_regHL); + break; + case 0xEF: SET<5>(_state.A); + break; + case 0xF0: SET<6>(_state.B); + break; + case 0xF1: SET<6>(_state.C); + break; + case 0xF2: SET<6>(_state.D); + break; + case 0xF3: SET<6>(_state.E); + break; + case 0xF4: SET<6>(_state.H); + break; + case 0xF5: SET<6>(_state.L); + break; + case 0xF6: SET_Indirect<6>(_regHL); + break; + case 0xF7: SET<6>(_state.A); + break; + case 0xF8: SET<7>(_state.B); + break; + case 0xF9: SET<7>(_state.C); + break; + case 0xFA: SET<7>(_state.D); + break; + case 0xFB: SET<7>(_state.E); + break; + case 0xFC: SET<7>(_state.H); + break; + case 0xFD: SET<7>(_state.L); + break; + case 0xFE: SET_Indirect<7>(_regHL); + break; + case 0xFF: SET<7>(_state.A); + break; } } @@ -1395,44 +1944,54 @@ void GbCpu::SetReg(GbRegister reg, uint16_t value) switch (reg) { case GbRegister::GbRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case GbRegister::GbRegSP: - { - _state.SP = value; - } break; + { + _state.SP = value; + } + break; case GbRegister::GbRegA: - { - _state.A = value & 0xFF; - } break; + { + _state.A = value & 0xFF; + } + break; case GbRegister::GbRegFlags: - { - _state.Flags = value & 0xFF; - } break; + { + _state.Flags = value & 0xFF; + } + break; case GbRegister::GbRegB: - { - _state.B = value & 0xFF; - } break; + { + _state.B = value & 0xFF; + } + break; case GbRegister::GbRegC: - { - _state.C = value & 0xFF; - } break; + { + _state.C = value & 0xFF; + } + break; case GbRegister::GbRegD: - { - _state.D = value & 0xFF; - } break; + { + _state.D = value & 0xFF; + } + break; case GbRegister::GbRegE: - { - _state.E = value & 0xFF; - } break; + { + _state.E = value & 0xFF; + } + break; case GbRegister::GbRegH: - { - _state.H = value & 0xFF; - } break; + { + _state.H = value & 0xFF; + } + break; case GbRegister::GbRegL: - { - _state.L = value & 0xFF; - } break; + { + _state.L = value & 0xFF; + } + break; } } diff --git a/Core/GbCpu.h b/Core/GbCpu.h index 474708c..89537b2 100644 --- a/Core/GbCpu.h +++ b/Core/GbCpu.h @@ -66,7 +66,7 @@ private: void AND(uint8_t value); void OR(uint8_t value); void XOR(uint8_t value); - + void CP(uint8_t value); void NOP(); @@ -98,19 +98,19 @@ private: void SWAP(uint8_t& dst); void SWAP_Indirect(uint16_t addr); - template + template void BIT(uint8_t src); - template + template void RES(uint8_t& dst); - template + template void RES_Indirect(uint16_t addr); - template + template void SET(uint8_t& dst); - template + template void SET_Indirect(uint16_t addr); void DAA(); @@ -127,7 +127,7 @@ private: void RET(bool condition); void RETI(); void RST(uint8_t value); - + void POP(Register16& reg); void PUSH(Register16& reg); void POP_AF(); @@ -148,7 +148,7 @@ public: bool IsHalted(); void Exec(); - + void Serialize(Serializer& s) override; void SetReg(GbRegister reg, uint16_t value); diff --git a/Core/GbDebugger.cpp b/Core/GbDebugger.cpp index 9fc5d56..a063de3 100644 --- a/Core/GbDebugger.cpp +++ b/Core/GbDebugger.cpp @@ -37,7 +37,8 @@ GbDebugger::GbDebugger(Debugger* debugger) _step.reset(new StepRequest()); _assembler.reset(new GbAssembler(debugger->GetLabelManager())); - if(_gameboy->GetState().MemoryManager.ApuCycleCount == 0) { + if (_gameboy->GetState().MemoryManager.ApuCycleCount == 0) + { //Enable breaking on uninit reads when debugger is opened at power on _enableBreakOnUninitRead = true; } @@ -56,21 +57,26 @@ void GbDebugger::Reset() void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; BreakSource breakSource = BreakSource::Unspecified; - if(type == MemoryOperationType::ExecOpCode) { + if (type == MemoryOperationType::ExecOpCode) + { GbCpuState gbState = _gameboy->GetState().Cpu; - if(_traceLogger->IsCpuLogged(CpuType::Gameboy) || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) { - if(addressInfo.Address >= 0) { - if(addressInfo.Type == SnesMemoryType::GbPrgRom) { + if (_traceLogger->IsCpuLogged(CpuType::Gameboy) || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) + { + if (addressInfo.Address >= 0) + { + if (addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code); } _disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy); } - if(_traceLogger->IsCpuLogged(CpuType::Gameboy)) { + if (_traceLogger->IsCpuLogged(CpuType::Gameboy)) + { DebugState debugState; _debugger->GetState(debugState, true); @@ -79,38 +85,58 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t } } - if(GameboyDisUtils::IsJumpToSub(_prevOpCode) && gbState.PC != _prevProgramCounter + GameboyDisUtils::GetOpSize(_prevOpCode)) { + if (GameboyDisUtils::IsJumpToSub(_prevOpCode) && gbState.PC != _prevProgramCounter + + GameboyDisUtils::GetOpSize(_prevOpCode)) + { //CALL and RST, and PC doesn't match the next instruction, so the call was (probably) done uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); uint16_t returnPc = _prevProgramCounter + opSize; AddressInfo src = _gameboy->GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = _gameboy->GetAbsoluteAddress(returnPc); - _callstackManager->Push(src, _prevProgramCounter, addressInfo, gbState.PC, ret, returnPc, StackFrameFlags::None); - } else if(GameboyDisUtils::IsReturnInstruction(_prevOpCode) && gbState.PC != _prevProgramCounter + GameboyDisUtils::GetOpSize(_prevOpCode)) { + _callstackManager->Push(src, _prevProgramCounter, addressInfo, gbState.PC, ret, returnPc, + StackFrameFlags::None); + } + else if (GameboyDisUtils::IsReturnInstruction(_prevOpCode) && gbState.PC != _prevProgramCounter + + GameboyDisUtils::GetOpSize(_prevOpCode)) + { //RET used, and PC doesn't match the next instruction, so the ret was (probably) taken _callstackManager->Pop(addressInfo, gbState.PC); } - if(_step->BreakAddress == (int32_t)gbState.PC && GameboyDisUtils::IsReturnInstruction(_prevOpCode)) { + if (_step->BreakAddress == (int32_t)gbState.PC && GameboyDisUtils::IsReturnInstruction(_prevOpCode)) + { //RET/RETI found, if we're on the expected return address, break immediately (for step over/step out) _step->StepCount = 0; } - if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) + { bool needBreak = false; - switch(value) { - case 0x40: - needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnNopLoad); - breakSource = BreakSource::GbNopLoad; - break; + switch (value) + { + case 0x40: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnNopLoad); + breakSource = BreakSource::GbNopLoad; + break; - case 0xD3: case 0xDB: case 0xDD: case 0xE3: case 0xE4: case 0xEB: case 0xEC: case 0xED: case 0xF4: case 0xFC: case 0xFD: - needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOpCode); - breakSource = BreakSource::GbInvalidOpCode; - break; + case 0xD3: + case 0xDB: + case 0xDD: + case 0xE3: + case 0xE4: + case 0xEB: + case 0xEC: + case 0xED: + case 0xF4: + case 0xFC: + case 0xFD: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOpCode); + breakSource = BreakSource::GbInvalidOpCode; + break; } - if(needBreak) { + if (needBreak) + { _step->StepCount = 0; } } @@ -118,30 +144,43 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t _prevOpCode = value; _prevProgramCounter = gbState.PC; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _console->GetMasterClock()); - } else if(type == MemoryOperationType::ExecOperand) { - if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) { + } + else if (type == MemoryOperationType::ExecOperand) + { + if (addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code); } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _console->GetMasterClock()); - } else { - if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) { + } + else + { + if (addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data); } - if(addr < 0xFE00 || addr >= 0xFF80) { - if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock())) { + if (addr < 0xFE00 || addr >= 0xFF80) + { + if (_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->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("[GB] Uninitialized memory read: $" + HexUtilities::ToHex(addr)); } - if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled) && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnUninitRead)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled) && _settings->CheckDebuggerFlag( + DebuggerFlags::BreakOnUninitRead)) + { breakSource = BreakSource::BreakOnUninitMemoryRead; _step->StepCount = 0; } @@ -149,25 +188,30 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t } } - if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + if (addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } } - _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource); + _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, + breakSource); } void GbDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); - if(addressInfo.Type == SnesMemoryType::GbWorkRam || addressInfo.Type == SnesMemoryType::GbCartRam || addressInfo.Type == SnesMemoryType::GbHighRam) { + if (addressInfo.Type == SnesMemoryType::GbWorkRam || addressInfo.Type == SnesMemoryType::GbCartRam || addressInfo. + Type == SnesMemoryType::GbHighRam) + { _disassembler->InvalidateCache(addressInfo, CpuType::Gameboy); } - if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + if (addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } @@ -184,24 +228,35 @@ void GbDebugger::Step(int32_t stepCount, StepType type) StepRequest step; GbCpuState gbState = _gameboy->GetState().Cpu; - if((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && gbState.Halted) { + if ((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && gbState.Halted) + { //CPU isn't running - use the PPU to break execution instead step.PpuStepCount = 1; - } else { - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; - case StepType::StepOver: - if(GameboyDisUtils::IsJumpToSub(_prevOpCode)) { - step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); - } else { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - break; + } + else + { + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; + case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); + break; + case StepType::StepOver: + if (GameboyDisUtils::IsJumpToSub(_prevOpCode)) + { + step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); + } + 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)); @@ -218,14 +273,17 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc) void GbDebugger::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); } @@ -254,4 +312,4 @@ shared_ptr GbDebugger::GetCodeDataLogger() BreakpointManager* GbDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/GbDebugger.h b/Core/GbDebugger.h index 8a9090a..eb7a525 100644 --- a/Core/GbDebugger.h +++ b/Core/GbDebugger.h @@ -55,4 +55,4 @@ public: shared_ptr GetCallstackManager(); shared_ptr GetCodeDataLogger(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/GbDmaController.cpp b/Core/GbDmaController.cpp index b089c11..5005d69 100644 --- a/Core/GbDmaController.cpp +++ b/Core/GbDmaController.cpp @@ -19,13 +19,16 @@ GbDmaControllerState GbDmaController::GetState() void GbDmaController::Exec() { - if(_cpu->IsHalted()) { + if (_cpu->IsHalted()) + { //OAM DMA is halted while the CPU is in halt mode, and resumes when the CPU resumes return; } - if(_state.DmaCounter > 0) { - if(_state.DmaCounter <= 160) { + if (_state.DmaCounter > 0) + { + if (_state.DmaCounter <= 160) + { _memoryManager->WriteDma(0xFE00 + (160 - _state.DmaCounter), _state.DmaReadBuffer); } @@ -33,8 +36,10 @@ void GbDmaController::Exec() _state.DmaReadBuffer = _memoryManager->ReadDma((_state.OamDmaSource << 8) + (160 - _state.DmaCounter)); } - if(_state.DmaStartDelay > 0) { - if(--_state.DmaStartDelay == 0) { + if (_state.DmaStartDelay > 0) + { + if (--_state.DmaStartDelay == 0) + { _state.InternalDest = _state.OamDmaSource; _state.DmaCounter = 161; } @@ -59,8 +64,9 @@ void GbDmaController::Write(uint8_t value) uint8_t GbDmaController::ReadCgb(uint16_t addr) { - switch(addr) { - case 0xFF55: return _state.CgbDmaLength | (_state.CgbHdmaDone ? 0x80 : 0); + switch (addr) + { + case 0xFF55: return _state.CgbDmaLength | (_state.CgbHdmaDone ? 0x80 : 0); } return 0; @@ -68,40 +74,55 @@ uint8_t GbDmaController::ReadCgb(uint16_t addr) void GbDmaController::WriteCgb(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF51: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF) | (value << 8); break; - case 0xFF52: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF00) | (value & 0xF0); break; - case 0xFF53: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF) | (value << 8); break; - case 0xFF54: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF00) | (value & 0xF0); break; - case 0xFF55: { + switch (addr) + { + case 0xFF51: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF) | (value << 8); + break; + case 0xFF52: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF00) | (value & 0xF0); + break; + case 0xFF53: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF) | (value << 8); + break; + case 0xFF54: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF00) | (value & 0xF0); + break; + case 0xFF55: + { bool hdmaMode = (value & 0x80) != 0; _state.CgbDmaLength = value & 0x7F; - if(!hdmaMode) { - if(_state.CgbHdmaRunning) { + if (!hdmaMode) + { + if (_state.CgbHdmaRunning) + { //"If HDMA5 is written during a HDMA copy, the behaviour depends on the written bit 7. // - New bit 7 is 0: Stop copy. HDMA5 new value is ( 80h OR written_value ). // - New bit 7 is 1: Restart copy. New size is the value of written_value bits 0-6. //This means that HDMA can't switch to GDMA with only one write. It must be stopped first." _state.CgbHdmaRunning = false; _state.CgbHdmaDone = true; - } else { + } + else + { //4 cycles for setup _memoryManager->Exec(); _memoryManager->Exec(); - do { + do + { ProcessDmaBlock(); - } while(_state.CgbDmaLength != 0x7F); + } + while (_state.CgbDmaLength != 0x7F); } - } else { + } + else + { //"After writing a value to HDMA5 that starts the HDMA copy, the upper bit (that indicates HDMA mode when set to '1') will be cleared" _state.CgbHdmaDone = false; _state.CgbHdmaRunning = true; //"If a HDMA transfer is started when the screen is off, one block is copied. " //" When a HDMA transfer is started during HBL it will start right away." - if(!_ppu->IsLcdEnabled() || _ppu->GetMode() == PpuMode::HBlank) { + if (!_ppu->IsLcdEnabled() || _ppu->GetMode() == PpuMode::HBlank) + { ProcessHdma(); } } @@ -112,7 +133,8 @@ void GbDmaController::WriteCgb(uint16_t addr, uint8_t value) void GbDmaController::ProcessHdma() { - if(_state.CgbHdmaRunning) { + if (_state.CgbHdmaRunning) + { //4 cycles for setup _memoryManager->Exec(); _memoryManager->Exec(); @@ -124,13 +146,15 @@ void GbDmaController::ProcessHdma() void GbDmaController::ProcessDmaBlock() { //TODO check invalid dma sources/etc. - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { uint16_t dst = 0x8000 | ((_state.CgbDmaDest + i) & 0x1FFF); //2 or 4 cycles per byte transfered (2x more cycles in high speed mode - effective speed is the same in both modes _memoryManager->Exec(); uint8_t value = _memoryManager->Read(_state.CgbDmaSource + i); - if(_memoryManager->IsHighSpeed()) { + if (_memoryManager->IsHighSpeed()) + { _memoryManager->Exec(); } _memoryManager->Write(dst, value); @@ -141,7 +165,8 @@ void GbDmaController::ProcessDmaBlock() _state.CgbDmaDest += 16; _state.CgbDmaLength = (_state.CgbDmaLength - 1) & 0x7F; - if(_state.CgbHdmaRunning && _state.CgbDmaLength == 0x7F) { + if (_state.CgbHdmaRunning && _state.CgbDmaLength == 0x7F) + { _state.CgbHdmaRunning = false; _state.CgbHdmaDone = true; } diff --git a/Core/GbDmaController.h b/Core/GbDmaController.h index 3eb13f9..98945a2 100644 --- a/Core/GbDmaController.h +++ b/Core/GbDmaController.h @@ -14,7 +14,7 @@ private: GbMemoryManager* _memoryManager; GbPpu* _ppu; GbCpu* _cpu; - + void ProcessDmaBlock(); public: @@ -35,4 +35,4 @@ public: void ProcessHdma(); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbEventManager.cpp b/Core/GbEventManager.cpp index aad38ad..df6f6ac 100644 --- a/Core/GbEventManager.cpp +++ b/Core/GbEventManager.cpp @@ -17,8 +17,8 @@ GbEventManager::GbEventManager(Debugger* debugger, GbCpu* cpu, GbPpu* ppu) _cpu = cpu; _ppu = ppu; - _ppuBuffer = new uint16_t[456*GbEventManager::ScreenHeight]; - memset(_ppuBuffer, 0, 456*GbEventManager::ScreenHeight * sizeof(uint16_t)); + _ppuBuffer = new uint16_t[456 * GbEventManager::ScreenHeight]; + memset(_ppuBuffer, 0, 456 * GbEventManager::ScreenHeight * sizeof(uint16_t)); } GbEventManager::~GbEventManager() @@ -63,8 +63,10 @@ DebugEventInfo GbEventManager::GetEvent(uint16_t scanline, uint16_t cycle, Event { 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; } } @@ -93,85 +95,132 @@ void GbEventManager::FilterEvents(EventViewerDisplayOptions& options) _sentEvents.clear(); vector 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; + for (DebugEventInfo& evt : events) + { + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == + MemoryOperationType::DmaWrite; bool showEvent = false; - switch(evt.Type) { - default: break; - case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; break; - case DebugEventType::Irq: showEvent = options.ShowIrq; break; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg >= 0xFE00 && reg <= 0xFE9F) { - showEvent = isWrite ? options.ShowPpuRegisterOamWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF42 && reg <= 0xFF43) { - showEvent = isWrite ? options.ShowPpuRegisterBgScrollWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0x8000 && reg <= 0x9FFF) { - showEvent = isWrite ? options.ShowPpuRegisterVramWrites : options.ShowPpuRegisterReads; - } else if((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) { - showEvent = isWrite ? options.ShowPpuRegisterCgramWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF4A && reg <= 0xFF4B) { - showEvent = isWrite ? options.ShowPpuRegisterWindowWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF40 && reg <= 0xFF70) { - showEvent = isWrite ? options.ShowPpuRegisterOtherWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF10 && reg <= 0xFF3F) { - showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; - } else { - showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; - } - break; + switch (evt.Type) + { + default: break; + case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; + break; + case DebugEventType::Irq: showEvent = options.ShowIrq; + break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg >= 0xFE00 && reg <= 0xFE9F) + { + showEvent = isWrite ? options.ShowPpuRegisterOamWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF42 && reg <= 0xFF43) + { + showEvent = isWrite ? options.ShowPpuRegisterBgScrollWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0x8000 && reg <= 0x9FFF) + { + showEvent = isWrite ? options.ShowPpuRegisterVramWrites : options.ShowPpuRegisterReads; + } + else if ((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) + { + showEvent = isWrite ? options.ShowPpuRegisterCgramWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF4A && reg <= 0xFF4B) + { + showEvent = isWrite ? options.ShowPpuRegisterWindowWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF40 && reg <= 0xFF70) + { + showEvent = isWrite ? options.ShowPpuRegisterOtherWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF10 && reg <= 0xFF3F) + { + showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; + } + else + { + showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; + } + break; } - if(showEvent) { + if (showEvent) + { _sentEvents.push_back(evt); } } } -void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options) +void GbEventManager::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; uint32_t ppuReadColor = options.PpuRegisterReadColor; - switch(evt.Type) { - default: break; - case DebugEventType::Breakpoint: color = options.BreakpointColor; break; - case DebugEventType::Irq: color = options.IrqColor; break; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg >= 0xFE00 && reg <= 0xFE9F) { - color = isWrite ? options.PpuRegisterWriteOamColor : ppuReadColor; - } else if(reg >= 0xFF42 && reg <= 0xFF43) { - color = isWrite ? options.PpuRegisterWriteBgScrollColor : ppuReadColor; - } else if(reg >= 0x8000 && reg <= 0x9FFF) { - color = isWrite ? options.PpuRegisterWriteVramColor : ppuReadColor; - } else if((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) { - color = isWrite ? options.PpuRegisterWriteCgramColor : ppuReadColor; - } else if(reg >= 0xFF4A && reg <= 0xFF4B) { - color = isWrite ? options.PpuRegisterWriteWindowColor : ppuReadColor; - } else if(reg >= 0xFF40 && reg <= 0xFF70) { - color = isWrite ? options.PpuRegisterWriteOtherColor : ppuReadColor; - } else if(reg >= 0xFF10 && reg <= 0xFF3F) { - color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; - } else { - color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; - } - break; + switch (evt.Type) + { + default: break; + case DebugEventType::Breakpoint: color = options.BreakpointColor; + break; + case DebugEventType::Irq: color = options.IrqColor; + break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg >= 0xFE00 && reg <= 0xFE9F) + { + color = isWrite ? options.PpuRegisterWriteOamColor : ppuReadColor; + } + else if (reg >= 0xFF42 && reg <= 0xFF43) + { + color = isWrite ? options.PpuRegisterWriteBgScrollColor : ppuReadColor; + } + else if (reg >= 0x8000 && reg <= 0x9FFF) + { + color = isWrite ? options.PpuRegisterWriteVramColor : ppuReadColor; + } + else if ((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) + { + color = isWrite ? options.PpuRegisterWriteCgramColor : ppuReadColor; + } + else if (reg >= 0xFF4A && reg <= 0xFF4B) + { + color = isWrite ? options.PpuRegisterWriteWindowColor : ppuReadColor; + } + else if (reg >= 0xFF40 && reg <= 0xFF70) + { + color = isWrite ? options.PpuRegisterWriteOtherColor : ppuReadColor; + } + else if (reg >= 0xFF10 && reg <= 0xFF3F) + { + color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; + } + else + { + color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; + } + break; } - if(drawBackground) { + if (drawBackground) + { color = 0xFF000000 | ((color >> 1) & 0x7F7F7F); - } else { + } + else + { color |= 0xFF000000; } @@ -182,10 +231,13 @@ void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_ uint32_t y = std::min(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) * GbEventManager::ScanlineWidth + x + j; - if(pos < 0 || pos >= GbEventManager::ScanlineWidth * (int)_scanlineCount * 2) { + if (pos < 0 || pos >= GbEventManager::ScanlineWidth * (int)_scanlineCount * 2) + { continue; } buffer[pos] = color; @@ -202,9 +254,12 @@ uint32_t GbEventManager::TakeEventSnapshot(EventViewerDisplayOptions options) uint16_t cycle = _ppu->GetState().Cycle; uint16_t scanline = _ppu->GetState().Scanline; - if(scanline >= GbEventManager::VBlankScanline || scanline == 0) { + if (scanline >= GbEventManager::VBlankScanline || scanline == 0) + { memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), 456 * GbEventManager::ScreenHeight * sizeof(uint16_t)); - } else { + } + else + { uint32_t size = 456 * GbEventManager::ScreenHeight; uint32_t offset = 456 * scanline; memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), offset * sizeof(uint16_t)); @@ -222,32 +277,39 @@ void GbEventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, Eve { auto lock = _lock.AcquireSafe(); - if(_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * GbEventManager::ScanlineWidth * 4) { + if (_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * GbEventManager::ScanlineWidth * 4) + { return; } - uint16_t *src = _ppuBuffer; - for(uint32_t y = 0, len = GbEventManager::ScreenHeight*2; y < len; y++) { - for(uint32_t x = 0; x < GbEventManager::ScanlineWidth; x++) { + uint16_t* src = _ppuBuffer; + for (uint32_t y = 0, len = GbEventManager::ScreenHeight * 2; y < len; y++) + { + for (uint32_t x = 0; x < GbEventManager::ScanlineWidth; x++) + { int srcOffset = (y >> 1) * 456 + (x >> 1); - buffer[y*GbEventManager::ScanlineWidth + x] = DefaultVideoFilter::ToArgb(src[srcOffset]); + buffer[y * GbEventManager::ScanlineWidth + x] = DefaultVideoFilter::ToArgb(src[srcOffset]); } } constexpr uint32_t currentScanlineColor = 0xFFFFFF55; uint32_t scanlineOffset = _snapshotScanline * 2 * GbEventManager::ScanlineWidth; - if(_snapshotScanline != 0) { - for(int i = 0; i < GbEventManager::ScanlineWidth; i++) { + if (_snapshotScanline != 0) + { + for (int i = 0; i < GbEventManager::ScanlineWidth; i++) + { buffer[scanlineOffset + i] = currentScanlineColor; buffer[scanlineOffset + GbEventManager::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); } } diff --git a/Core/GbEventManager.h b/Core/GbEventManager.h index 29ea6f2..cd2b5f1 100644 --- a/Core/GbEventManager.h +++ b/Core/GbEventManager.h @@ -14,7 +14,7 @@ class Debugger; class GbEventManager final : public IEventManager { private: - static constexpr int ScanlineWidth = 456*2; + static constexpr int ScanlineWidth = 456 * 2; static constexpr int ScreenHeight = 154; static constexpr int VBlankScanline = 144; diff --git a/Core/GbMbc1.h b/Core/GbMbc1.h index 23c75d2..a85f7ec 100644 --- a/Core/GbMbc1.h +++ b/Core/GbMbc1.h @@ -26,13 +26,16 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, (_mode ? (_ramBank << 5) : 0) * prgBankSize, true); uint8_t prgBank = _prgBank | (_ramBank << 5); - Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, prgBank*prgBankSize, true); + Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, prgBank * prgBankSize, true); - if(_ramEnabled) { + if (_ramEnabled) + { uint8_t ramBank = _mode ? _ramBank : 0; - Map(0xA000, 0xBFFF, GbMemoryType::CartRam, ramBank*ramBankSize, false); + Map(0xA000, 0xBFFF, GbMemoryType::CartRam, ramBank * ramBankSize, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -46,11 +49,16 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - switch(addr & 0x6000) { - case 0x0000: _ramEnabled = ((value & 0x0F) == 0x0A); break; - case 0x2000: _prgBank = std::max(1, value & 0x1F); break; - case 0x4000: _ramBank = value & 0x03; break; - case 0x6000: _mode = (value & 0x01) != 0; break; + switch (addr & 0x6000) + { + case 0x0000: _ramEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x2000: _prgBank = std::max(1, value & 0x1F); + break; + case 0x4000: _ramBank = value & 0x03; + break; + case 0x6000: _mode = (value & 0x01) != 0; + break; } RefreshMappings(); } @@ -59,4 +67,4 @@ public: { s.Stream(_ramEnabled, _prgBank, _ramBank, _mode); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc2.h b/Core/GbMbc2.h index c1677c1..15808e7 100644 --- a/Core/GbMbc2.h +++ b/Core/GbMbc2.h @@ -14,8 +14,9 @@ public: void InitCart() override { _memoryManager->MapRegisters(0x0000, 0x3FFF, RegisterAccess::Write); - - for(int i = 0; i < 512; i++) { + + for (int i = 0; i < 512; i++) + { //Ensure cart RAM contains $F in the upper nibble, no matter the contents of save ram _cartRam[i] |= 0xF0; } @@ -29,12 +30,16 @@ public: Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramEnabled) { - for(int i = 0; i < 16; i++) { - Map(0xA000+0x200*i, 0xA1FF+0x200*i, GbMemoryType::CartRam, 0, false); + if (_ramEnabled) + { + for (int i = 0; i < 16; i++) + { + Map(0xA000 + 0x200 * i, 0xA1FF + 0x200 * i, GbMemoryType::CartRam, 0, false); } _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Write); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -48,14 +53,20 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - if(addr >= 0xA000 && addr <= 0xBFFF) { + if (addr >= 0xA000 && addr <= 0xBFFF) + { //Cut off the top 4 bits for all cart ram writes //Set top nibble to $F to mimic open bus _cartRam[addr & 0x1FF] = (value & 0x0F) | 0xF0; - } else { - switch(addr & 0x100) { - case 0x000: _ramEnabled = ((value & 0x0F) == 0x0A); break; - case 0x100: _prgBank = std::max(1, value & 0x0F); break; + } + else + { + switch (addr & 0x100) + { + case 0x000: _ramEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x100: _prgBank = std::max(1, value & 0x0F); + break; } RefreshMappings(); } @@ -65,4 +76,4 @@ public: { s.Stream(_ramEnabled, _prgBank); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc3.h b/Core/GbMbc3.h index 75535df..9f4f02f 100644 --- a/Core/GbMbc3.h +++ b/Core/GbMbc3.h @@ -32,12 +32,17 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, 0, true); Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramRtcEnabled && _ramBank <= 3) { + if (_ramRtcEnabled && _ramBank <= 3) + { Map(0xA000, 0xBFFF, GbMemoryType::CartRam, _ramBank, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else if(_hasRtcTimer && _ramRtcEnabled && _ramBank >= 0x08 && _ramBank <= 0x0C) { + } + else if (_hasRtcTimer && _ramRtcEnabled && _ramBank >= 0x08 && _ramBank <= 0x0C) + { _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::ReadWrite); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -45,18 +50,20 @@ public: uint8_t ReadRegister(uint16_t addr) override { - if(_ramRtcEnabled) { + if (_ramRtcEnabled) + { //Disabled RAM/RTC registers returns 0xFF on reads (?) return 0xFF; } - + //RTC register read (TODO) - switch(_ramBank) { - case 0x08: return _rtcRegisters[0]; //Seconds - case 0x09: return _rtcRegisters[1]; //Minutes - case 0x0A: return _rtcRegisters[2]; //Hours - case 0x0B: return _rtcRegisters[3]; //Day counter - case 0x0C: return _rtcRegisters[4]; //Day counter (upper bit) + carry/halt flags + switch (_ramBank) + { + case 0x08: return _rtcRegisters[0]; //Seconds + case 0x09: return _rtcRegisters[1]; //Minutes + case 0x0A: return _rtcRegisters[2]; //Hours + case 0x0B: return _rtcRegisters[3]; //Day counter + case 0x0C: return _rtcRegisters[4]; //Day counter (upper bit) + carry/halt flags } //Not reached @@ -65,24 +72,37 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - if(addr <= 0x7FFF) { - switch(addr & 0x6000) { - case 0x0000: _ramRtcEnabled = ((value & 0x0F) == 0x0A); break; - case 0x2000: _prgBank = std::max(1, value); break; - case 0x4000: _ramBank = value & 0x0F; break; - case 0x6000: - //RTC register read latch - break; + if (addr <= 0x7FFF) + { + switch (addr & 0x6000) + { + case 0x0000: _ramRtcEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x2000: _prgBank = std::max(1, value); + break; + case 0x4000: _ramBank = value & 0x0F; + break; + case 0x6000: + //RTC register read latch + break; } RefreshMappings(); - } else if(addr >= 0xA000 && addr <= 0xBFFF) { + } + else if (addr >= 0xA000 && addr <= 0xBFFF) + { //RTC register write (TODO) - switch(_ramBank) { - case 0x08: _rtcRegisters[0] = value; break; //Seconds - case 0x09: _rtcRegisters[1] = value; break; //Minutes - case 0x0A: _rtcRegisters[2] = value; break; //Hours - case 0x0B: _rtcRegisters[3] = value; break; //Day counter - case 0x0C: _rtcRegisters[4] = value; break; //Day counter (upper bit) + carry/halt flags + switch (_ramBank) + { + case 0x08: _rtcRegisters[0] = value; + break; //Seconds + case 0x09: _rtcRegisters[1] = value; + break; //Minutes + case 0x0A: _rtcRegisters[2] = value; + break; //Hours + case 0x0B: _rtcRegisters[3] = value; + break; //Day counter + case 0x0C: _rtcRegisters[4] = value; + break; //Day counter (upper bit) + carry/halt flags } } } @@ -92,4 +112,4 @@ public: s.Stream(_ramRtcEnabled, _prgBank, _ramBank); s.StreamArray(_rtcRegisters, 5); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc5.h b/Core/GbMbc5.h index 163eb8e..db7b192 100644 --- a/Core/GbMbc5.h +++ b/Core/GbMbc5.h @@ -25,10 +25,13 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, 0, true); Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramEnabled) { + if (_ramEnabled) + { Map(0xA000, 0xBFFF, GbMemoryType::CartRam, _ramBank * ramBankSize, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -42,24 +45,25 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - switch(addr & 0x7000) { - case 0x0000: - case 0x1000: - _ramEnabled = (value == 0x0A); - break; - - case 0x2000: - _prgBank = (value & 0xFF) | (_prgBank & 0x100); - break; + switch (addr & 0x7000) + { + case 0x0000: + case 0x1000: + _ramEnabled = (value == 0x0A); + break; - case 0x3000: - _prgBank = (_prgBank & 0xFF) | ((value & 0x01) << 8); - break; + case 0x2000: + _prgBank = (value & 0xFF) | (_prgBank & 0x100); + break; - case 0x4000: - case 0x5000: - _ramBank = value & 0x0F; - break; + case 0x3000: + _prgBank = (_prgBank & 0xFF) | ((value & 0x01) << 8); + break; + + case 0x4000: + case 0x5000: + _ramBank = value & 0x0F; + break; } RefreshMappings(); } @@ -68,4 +72,4 @@ public: { s.Stream(_ramEnabled, _prgBank, _ramBank); } -}; \ No newline at end of file +}; diff --git a/Core/GbMemoryManager.cpp b/Core/GbMemoryManager.cpp index 220496a..17e9a4b 100644 --- a/Core/GbMemoryManager.cpp +++ b/Core/GbMemoryManager.cpp @@ -18,7 +18,8 @@ #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" -void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, GbDmaController* dmaController) +void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, + GbDmaController* dmaController) { _highRam = gameboy->DebugGetMemory(SnesMemoryType::GbHighRam); @@ -65,9 +66,11 @@ void GbMemoryManager::RefreshMappings() _cart->RefreshMappings(); - if(!_state.DisableBootRom) { + if (!_state.DisableBootRom) + { Map(0x0000, 0x00FF, GbMemoryType::BootRom, 0, true); - if(_gameboy->IsCgb()) { + if (_gameboy->IsCgb()) + { Map(0x0200, 0x08FF, GbMemoryType::BootRom, 0x200, true); } } @@ -79,13 +82,16 @@ void GbMemoryManager::Exec() _state.ApuCycleCount += _state.CgbHighSpeed ? 1 : 2; _timer->Exec(); _ppu->Exec(); - if((_state.CycleCount & 0x03) == 0) { + if ((_state.CycleCount & 0x03) == 0) + { _dmaController->Exec(); } - if(_state.SerialBitCount && (_state.CycleCount & 0x1FF) == 0) { + if (_state.SerialBitCount && (_state.CycleCount & 0x1FF) == 0) + { _state.SerialData = (_state.SerialData << 1) | 0x01; - if(--_state.SerialBitCount == 0) { + if (--_state.SerialBitCount == 0) + { //"It will be notified that the transfer is complete in two ways: //SC's Bit 7 will be cleared" _state.SerialControl &= 0x7F; @@ -98,7 +104,8 @@ void GbMemoryManager::Exec() void GbMemoryManager::MapRegisters(uint16_t start, uint16_t end, RegisterAccess access) { - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _state.IsReadRegister[i >> 8] = ((int)access & (int)RegisterAccess::Read) != 0; _state.IsWriteRegister[i >> 8] = ((int)access & (int)RegisterAccess::Write) != 0; } @@ -109,13 +116,16 @@ void GbMemoryManager::Map(uint16_t start, uint16_t end, GbMemoryType type, uint3 uint8_t* src = _gameboy->DebugGetMemory((SnesMemoryType)type); uint32_t size = _gameboy->DebugGetMemorySize((SnesMemoryType)type); - if(size > 0) { - while(offset >= size) { + if (size > 0) + { + while (offset >= size) + { offset -= size; } - + src += offset; - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _reads[i >> 8] = src; _writes[i >> 8] = readonly ? nullptr : src; @@ -123,23 +133,28 @@ void GbMemoryManager::Map(uint16_t start, uint16_t end, GbMemoryType type, uint3 _state.MemoryOffset[i >> 8] = offset; _state.MemoryAccessType[i >> 8] = readonly ? RegisterAccess::Read : RegisterAccess::ReadWrite; - if(src) { + if (src) + { src += 0x100; offset = (offset + 0x100); - if(offset >= size) { + if (offset >= size) + { offset = 0; src = _gameboy->DebugGetMemory((SnesMemoryType)type); } } } - } else { + } + else + { Unmap(start, end); } } void GbMemoryManager::Unmap(uint16_t start, uint16_t end) { - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _reads[i >> 8] = nullptr; _writes[i >> 8] = nullptr; @@ -149,13 +164,16 @@ void GbMemoryManager::Unmap(uint16_t start, uint16_t end) } } -template +template uint8_t GbMemoryManager::Read(uint16_t addr) { uint8_t value = 0; - if(_state.IsReadRegister[addr >> 8]) { + if (_state.IsReadRegister[addr >> 8]) + { value = ReadRegister(addr); - } else if(_reads[addr >> 8]) { + } + else if (_reads[addr >> 8]) + { value = _reads[addr >> 8][(uint8_t)addr]; } _console->ProcessMemoryRead(addr, value, opType); @@ -176,36 +194,48 @@ void GbMemoryManager::WriteDma(uint16_t addr, uint8_t value) uint8_t GbMemoryManager::ReadDma(uint16_t addr) { uint8_t value = 0; - if(_reads[addr >> 8]) { + if (_reads[addr >> 8]) + { value = _reads[addr >> 8][(uint8_t)addr]; - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { value = ReadRegister(addr); } _console->ProcessMemoryRead(addr, value, MemoryOperationType::DmaRead); return value; } -template +template void GbMemoryManager::Write(uint16_t addr, uint8_t value) { _console->ProcessMemoryWrite(addr, value, type); - if(_state.IsWriteRegister[addr >> 8]) { + if (_state.IsWriteRegister[addr >> 8]) + { WriteRegister(addr, value); - } else if(_writes[addr >> 8]) { + } + else if (_writes[addr >> 8]) + { _writes[addr >> 8][(uint8_t)addr] = value; } } uint8_t GbMemoryManager::DebugRead(uint16_t addr) { - if(_state.IsReadRegister[addr >> 8]) { - if(addr >= 0xFE00) { + if (_state.IsReadRegister[addr >> 8]) + { + if (addr >= 0xFE00) + { return PeekRegister(addr); - } else { + } + else + { //Avoid potential read side effects return 0xFF; } - } else if(_reads[addr >> 8]) { + } + else if (_reads[addr >> 8]) + { return _reads[addr >> 8][(uint8_t)addr]; } return 0; @@ -213,16 +243,20 @@ uint8_t GbMemoryManager::DebugRead(uint16_t addr) void GbMemoryManager::DebugWrite(uint16_t addr, uint8_t value) { - if(_state.IsWriteRegister[addr >> 8]) { + if (_state.IsWriteRegister[addr >> 8]) + { //Do not write to registers via debug tools - } else if(_writes[addr >> 8]) { + } + else if (_writes[addr >> 8]) + { _writes[addr >> 8][(uint8_t)addr] = value; } } uint8_t* GbMemoryManager::GetMappedBlock(uint16_t addr) { - if(_reads[addr >> 8]) { + if (_reads[addr >> 8]) + { return _reads[addr >> 8]; } return nullptr; @@ -231,89 +265,128 @@ uint8_t* GbMemoryManager::GetMappedBlock(uint16_t addr) uint8_t GbMemoryManager::PeekRegister(uint16_t addr) { //Peek on oam/vram to avoid triggering the invalid oam/vram access break options - if(addr >= 0xFE00 && addr <= 0xFE9F) { + if (addr >= 0xFE00 && addr <= 0xFE9F) + { return _ppu->PeekOam((uint8_t)addr); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { return _ppu->PeekVram(addr); - } else if(addr >= 0xFF10 && addr <= 0xFF3F) { + } + else if (addr >= 0xFF10 && addr <= 0xFF3F) + { return _apu->Peek(addr); - } else { + } + else + { return ReadRegister(addr); } } uint8_t GbMemoryManager::ReadRegister(uint16_t addr) { - if(addr >= 0xFF00) { - if(addr == 0xFFFF) { + if (addr >= 0xFF00) + { + if (addr == 0xFFFF) + { return _state.IrqEnabled; //IE - Interrupt Enable (R/W) - } else if(addr == 0xFF46) { + } + else if (addr == 0xFF46) + { return _dmaController->Read(); - } else if(addr >= 0xFF80) { + } + else if (addr >= 0xFF80) + { return _highRam[addr & 0x7F]; //80-FE - } else if(addr >= 0xFF4C) { - if(_gameboy->IsCgb()) { - switch(addr) { + } + else if (addr >= 0xFF4C) + { + if (_gameboy->IsCgb()) + { + switch (addr) + { //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch - case 0xFF4D: - if(_ppu->IsCgbEnabled()) { - return ( - (_state.CgbHighSpeed ? 0x80 : 0) | - (_state.CgbSwitchSpeedRequest ? 0x01 : 0) | - 0x7E - ); - } - return 0xFF; - - case 0xFF55: //CGB - DMA - return _ppu->IsCgbEnabled() ? _dmaController->ReadCgb(addr) : 0xFF; + case 0xFF4D: + if (_ppu->IsCgbEnabled()) + { + return ( + (_state.CgbHighSpeed ? 0x80 : 0) | + (_state.CgbSwitchSpeedRequest ? 0x01 : 0) | + 0x7E + ); + } + return 0xFF; - case 0xFF4F: //CGB - VRAM bank - case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette - return _ppu->ReadCgbRegister(addr); + case 0xFF55: //CGB - DMA + return _ppu->IsCgbEnabled() ? _dmaController->ReadCgb(addr) : 0xFF; + + case 0xFF4F: //CGB - VRAM bank + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: //CGB - Palette + return _ppu->ReadCgbRegister(addr); //FF70 - SVBK - CGB Mode Only - WRAM Bank - case 0xFF70: return _ppu->IsCgbEnabled() ? (_state.CgbWorkRamBank | 0xF8) : 0xFF; - case 0xFF72: return _state.CgbRegFF72; - case 0xFF73: return _state.CgbRegFF73; - - case 0xFF74: - if(_ppu->IsCgbEnabled()) { - return _state.CgbRegFF74; - } - return 0xFF; + case 0xFF70: return _ppu->IsCgbEnabled() ? (_state.CgbWorkRamBank | 0xF8) : 0xFF; + case 0xFF72: return _state.CgbRegFF72; + case 0xFF73: return _state.CgbRegFF73; - case 0xFF75: return _state.CgbRegFF75 | 0x8F; - - case 0xFF76: case 0xFF77: - return _apu->ReadCgbRegister(addr); + case 0xFF74: + if (_ppu->IsCgbEnabled()) + { + return _state.CgbRegFF74; + } + return 0xFF; + + case 0xFF75: return _state.CgbRegFF75 | 0x8F; + + case 0xFF76: + case 0xFF77: + return _apu->ReadCgbRegister(addr); } } LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; //4C-7F, open bus - } else if(addr >= 0xFF40) { + } + else if (addr >= 0xFF40) + { return _ppu->Read(addr); //40-4B - } else if(addr >= 0xFF10) { + } + else if (addr >= 0xFF10) + { return _apu->Read(addr); //10-3F - } else { + } + else + { //00-0F - switch(addr) { - case 0xFF00: return ReadInputPort(); break; - - case 0xFF01: return _state.SerialData; //SB - Serial transfer data (R/W) - case 0xFF02: return _state.SerialControl | 0x7E; //SC - Serial Transfer Control (R/W) + switch (addr) + { + case 0xFF00: return ReadInputPort(); + break; - case 0xFF04: case 0xFF05: case 0xFF06: case 0xFF07: - return _timer->Read(addr); + case 0xFF01: return _state.SerialData; //SB - Serial transfer data (R/W) + case 0xFF02: return _state.SerialControl | 0x7E; //SC - Serial Transfer Control (R/W) - case 0xFF0F: return _state.IrqRequests | 0xE0; break; //IF - Interrupt flags (R/W) + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + return _timer->Read(addr); - default: return 0xFF; //Open bus + case 0xFF0F: return _state.IrqRequests | 0xE0; + break; //IF - Interrupt flags (R/W) + + default: return 0xFF; //Open bus } } - } else if(addr >= 0xFE00) { + } + else if (addr >= 0xFE00) + { return _ppu->ReadOam((uint8_t)addr); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { return _ppu->ReadVram(addr); } @@ -322,100 +395,150 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr) void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value) { - if(addr >= 0xFF00) { - if(addr == 0xFFFF) { + if (addr >= 0xFF00) + { + if (addr == 0xFFFF) + { _state.IrqEnabled = value; //IE register - } else if(addr == 0xFF46) { + } + else if (addr == 0xFF46) + { _dmaController->Write(value); - } else if(addr >= 0xFF80) { + } + else if (addr >= 0xFF80) + { _highRam[addr & 0x7F] = value; //80-FE - } else if(addr >= 0xFF4C) { + } + else if (addr >= 0xFF4C) + { //4C-7F - if(addr == 0xFF50) { - if(value & 0x01) { + if (addr == 0xFF50) + { + if (value & 0x01) + { _state.DisableBootRom = true; RefreshMappings(); } - } else if(_gameboy->IsCgb()) { - switch(addr) { - case 0xFF4D: - //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch - if(_ppu->IsCgbEnabled()) { - _state.CgbSwitchSpeedRequest = (value & 0x01) != 0; - } - break; - - case 0xFF51: case 0xFF52: case 0xFF53: case 0xFF54: case 0xFF55: //CGB - DMA - if(_ppu->IsCgbEnabled()) { - _dmaController->WriteCgb(addr, value); - } - break; - - case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games - if(!_state.DisableBootRom) { - _ppu->WriteCgbRegister(addr, value); - } - break; - - case 0xFF4F: //CGB - VRAM banking - case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette - _ppu->WriteCgbRegister(addr, value); - break; - - case 0xFF70: - //FF70 - SVBK - CGB Mode Only - WRAM Bank - if(_ppu->IsCgbEnabled()) { - _state.CgbWorkRamBank = std::max(1, value & 0x07); - RefreshMappings(); - } - break; - - case 0xFF72: _state.CgbRegFF72 = value; break; - case 0xFF73: _state.CgbRegFF73 = value; break; - case 0xFF74: - if(_ppu->IsCgbEnabled()) { - _state.CgbRegFF74 = value; - } - break; - - case 0xFF75: _state.CgbRegFF75 = value; break; - - default: - LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; - } } - } else if(addr >= 0xFF40) { - _ppu->Write(addr, value); //40-4B - } else if(addr >= 0xFF10) { - _apu->Write(addr, value); //10-3F - } else { - //00-0F - switch(addr) { - case 0xFF00: WriteInputPort(value); break; - case 0xFF01: _state.SerialData = value; break; //FF01 - SB - Serial transfer data (R/W) - case 0xFF02: - //FF02 - SC - Serial Transfer Control (R/W) - _state.SerialControl = value & (_gameboy->IsCgb() ? 0x83 : 0x81); - if((_state.SerialControl & 0x80) && (_state.SerialControl & 0x01)) { - _state.SerialBitCount = 8; - } else { - _state.SerialBitCount = 0; + else if (_gameboy->IsCgb()) + { + switch (addr) + { + case 0xFF4D: + //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch + if (_ppu->IsCgbEnabled()) + { + _state.CgbSwitchSpeedRequest = (value & 0x01) != 0; } break; - case 0xFF04: case 0xFF05: case 0xFF06: case 0xFF07: - _timer->Write(addr, value); + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: //CGB - DMA + if (_ppu->IsCgbEnabled()) + { + _dmaController->WriteCgb(addr, value); + } break; - case 0xFF0F: _state.IrqRequests = value & 0x1F; break; //IF - Interrupt flags (R/W) + case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games + if (!_state.DisableBootRom) + { + _ppu->WriteCgbRegister(addr, value); + } + break; + + case 0xFF4F: //CGB - VRAM banking + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: //CGB - Palette + _ppu->WriteCgbRegister(addr, value); + break; + + case 0xFF70: + //FF70 - SVBK - CGB Mode Only - WRAM Bank + if (_ppu->IsCgbEnabled()) + { + _state.CgbWorkRamBank = std::max(1, value & 0x07); + RefreshMappings(); + } + break; + + case 0xFF72: _state.CgbRegFF72 = value; + break; + case 0xFF73: _state.CgbRegFF73 = value; + break; + case 0xFF74: + if (_ppu->IsCgbEnabled()) + { + _state.CgbRegFF74 = value; + } + break; + + case 0xFF75: _state.CgbRegFF75 = value; + break; + + default: + LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; + } } } - } else if(addr >= 0xFE00) { + else if (addr >= 0xFF40) + { + _ppu->Write(addr, value); //40-4B + } + else if (addr >= 0xFF10) + { + _apu->Write(addr, value); //10-3F + } + else + { + //00-0F + switch (addr) + { + case 0xFF00: WriteInputPort(value); + break; + case 0xFF01: _state.SerialData = value; + break; //FF01 - SB - Serial transfer data (R/W) + case 0xFF02: + //FF02 - SC - Serial Transfer Control (R/W) + _state.SerialControl = value & (_gameboy->IsCgb() ? 0x83 : 0x81); + if ((_state.SerialControl & 0x80) && (_state.SerialControl & 0x01)) + { + _state.SerialBitCount = 8; + } + else + { + _state.SerialBitCount = 0; + } + break; + + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + _timer->Write(addr, value); + break; + + case 0xFF0F: _state.IrqRequests = value & 0x1F; + break; //IF - Interrupt flags (R/W) + } + } + } + else if (addr >= 0xFE00) + { _ppu->WriteOam((uint8_t)addr, value, false); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { _ppu->WriteVram(addr, value); - } else { + } + else + { _cart->WriteRegister(addr, value); } } @@ -433,16 +556,26 @@ void GbMemoryManager::ClearIrqRequest(uint8_t source) uint8_t GbMemoryManager::ProcessIrqRequests() { uint8_t irqsToProcess = _state.IrqRequests & _state.IrqEnabled; - if(irqsToProcess) { - if(irqsToProcess & GbIrqSource::VerticalBlank) { + if (irqsToProcess) + { + if (irqsToProcess & GbIrqSource::VerticalBlank) + { return GbIrqSource::VerticalBlank; - } else if(irqsToProcess & GbIrqSource::LcdStat) { + } + else if (irqsToProcess & GbIrqSource::LcdStat) + { return GbIrqSource::LcdStat; - } else if(irqsToProcess & GbIrqSource::Timer) { + } + else if (irqsToProcess & GbIrqSource::Timer) + { return GbIrqSource::Timer; - } else if(irqsToProcess & GbIrqSource::Serial) { + } + else if (irqsToProcess & GbIrqSource::Serial) + { return GbIrqSource::Serial; - } else if(irqsToProcess & GbIrqSource::Joypad) { + } + else if (irqsToProcess & GbIrqSource::Joypad) + { return GbIrqSource::Joypad; } } @@ -487,28 +620,39 @@ uint8_t GbMemoryManager::ReadInputPort() //Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only) uint8_t result = 0x0F; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); - if((_state.InputSelect & 0x30) == 0x30) { + if ((_state.InputSelect & 0x30) == 0x30) + { result = sgb->GetInputIndex(); - } else { - if(!(_state.InputSelect & 0x20)) { + } + else + { + if (!(_state.InputSelect & 0x20)) + { result &= sgb->GetInput() >> 4; } - if(!(_state.InputSelect & 0x10)) { + if (!(_state.InputSelect & 0x10)) + { result &= sgb->GetInput() & 0x0F; } } - } else { + } + else + { BaseControlDevice* controller = (SnesController*)_controlManager->GetControlDevice(0).get(); - if(controller && controller->GetControllerType() == ControllerType::SnesController) { - if(!(_state.InputSelect & 0x20)) { + if (controller && controller->GetControllerType() == ControllerType::SnesController) + { + if (!(_state.InputSelect & 0x20)) + { result &= ~(controller->IsPressed(SnesController::A) ? 0x01 : 0); result &= ~(controller->IsPressed(SnesController::B) ? 0x02 : 0); result &= ~(controller->IsPressed(SnesController::Select) ? 0x04 : 0); result &= ~(controller->IsPressed(SnesController::Start) ? 0x08 : 0); } - if(!(_state.InputSelect & 0x10)) { + if (!(_state.InputSelect & 0x10)) + { result &= ~(controller->IsPressed(SnesController::Right) ? 0x01 : 0); result &= ~(controller->IsPressed(SnesController::Left) ? 0x02 : 0); result &= ~(controller->IsPressed(SnesController::Up) ? 0x04 : 0); @@ -523,7 +667,8 @@ uint8_t GbMemoryManager::ReadInputPort() void GbMemoryManager::WriteInputPort(uint8_t value) { _state.InputSelect = value; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { _console->GetCartridge()->GetSuperGameboy()->ProcessInputPortWrite(value & 0x30); } } @@ -542,10 +687,13 @@ void GbMemoryManager::Serialize(Serializer& s) s.StreamArray(_state.IsReadRegister, 0x100); s.StreamArray(_state.IsWriteRegister, 0x100); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { //Restore mappings based on state - for(int i = 0; i < 0x100; i++) { - Map(i*0x100, i*0x100+0xFF, _state.MemoryType[i], _state.MemoryOffset[i], _state.MemoryAccessType[i] == RegisterAccess::ReadWrite ? false : true); + for (int i = 0; i < 0x100; i++) + { + Map(i * 0x100, i * 0x100 + 0xFF, _state.MemoryType[i], _state.MemoryOffset[i], + _state.MemoryAccessType[i] == RegisterAccess::ReadWrite ? false : true); } RefreshMappings(); } @@ -556,4 +704,4 @@ template uint8_t GbMemoryManager::Read(uint16_t template uint8_t GbMemoryManager::Read(uint16_t addr); template uint8_t GbMemoryManager::Read(uint16_t addr); template void GbMemoryManager::Write(uint16_t addr, uint8_t value); -template void GbMemoryManager::Write(uint16_t addr, uint8_t value); \ No newline at end of file +template void GbMemoryManager::Write(uint16_t addr, uint8_t value); diff --git a/Core/GbMemoryManager.h b/Core/GbMemoryManager.h index 27c150b..8bb0383 100644 --- a/Core/GbMemoryManager.h +++ b/Core/GbMemoryManager.h @@ -31,7 +31,7 @@ private: GbDmaController* _dmaController = nullptr; uint8_t* _highRam = nullptr; - + uint8_t* _reads[0x100] = {}; uint8_t* _writes[0x100] = {}; @@ -42,7 +42,8 @@ public: GbMemoryManagerState GetState(); - void Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, GbDmaController* dmaController); + void Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, + GbDmaController* dmaController); void MapRegisters(uint16_t start, uint16_t end, RegisterAccess access); void Map(uint16_t start, uint16_t end, GbMemoryType type, uint32_t offset, bool readonly); void Unmap(uint16_t start, uint16_t end); @@ -50,14 +51,14 @@ public: void Exec(); - template + template uint8_t Read(uint16_t addr); bool IsOamDmaRunning(); void WriteDma(uint16_t addr, uint8_t value); uint8_t ReadDma(uint16_t addr); - template + template void Write(uint16_t addr, uint8_t value); uint8_t PeekRegister(uint16_t addr); @@ -74,7 +75,7 @@ public: uint64_t GetCycleCount(); uint64_t GetApuCycleCount(); - + uint8_t ReadInputPort(); void WriteInputPort(uint8_t value); diff --git a/Core/GbNoiseChannel.cpp b/Core/GbNoiseChannel.cpp index 4d95426..509a66f 100644 --- a/Core/GbNoiseChannel.cpp +++ b/Core/GbNoiseChannel.cpp @@ -26,9 +26,11 @@ void GbNoiseChannel::Disable() void GbNoiseChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -37,13 +39,18 @@ void GbNoiseChannel::ClockLengthCounter() void GbNoiseChannel::ClockEnvelope() { - if(_state.EnvTimer > 0) { + if (_state.EnvTimer > 0) + { _state.EnvTimer--; - if(_state.EnvTimer == 0) { - if(_state.EnvRaiseVolume && _state.Volume < 0x0F) { + if (_state.EnvTimer == 0) + { + if (_state.EnvRaiseVolume && _state.Volume < 0x0F) + { _state.Volume++; - } else if(!_state.EnvRaiseVolume && _state.Volume > 0) { + } + else if (!_state.EnvRaiseVolume && _state.Volume > 0) + { _state.Volume--; } @@ -59,29 +66,37 @@ uint8_t GbNoiseChannel::GetOutput() uint32_t GbNoiseChannel::GetPeriod() { - if(_state.Divisor == 0) { + if (_state.Divisor == 0) + { return 8 << _state.PeriodShift; - } else { + } + else + { return (16 * _state.Divisor) << _state.PeriodShift; } } void GbNoiseChannel::Exec(uint32_t clocksToRun) { - if(_state.PeriodShift >= 14) { + if (_state.PeriodShift >= 14) + { //Using a noise channel clock shift of 14 or 15 results in the LFSR receiving no clocks. return; } _state.Timer -= clocksToRun; - if(_state.Enabled) { + if (_state.Enabled) + { _state.Output = ((_state.ShiftRegister & 0x01) ^ 0x01) * _state.Volume; - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { _state.Timer = GetPeriod(); //When clocked by the frequency timer, the low two bits (0 and 1) are XORed, all bits are shifted right by one, @@ -90,7 +105,8 @@ void GbNoiseChannel::Exec(uint32_t clocksToRun) uint8_t xorResult = (_state.ShiftRegister & 0x01) ^ (shiftedValue & 0x01); _state.ShiftRegister = (xorResult << 14) | shiftedValue; - if(_state.ShortWidthMode) { + if (_state.ShortWidthMode) + { //If width mode is 1 (NR43), the XOR result is ALSO put into bit 6 AFTER the shift, resulting in a 7-bit LFSR. _state.ShiftRegister &= ~0x40; _state.ShiftRegister |= (xorResult << 6); @@ -100,27 +116,29 @@ void GbNoiseChannel::Exec(uint32_t clocksToRun) uint8_t GbNoiseChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0xFF, 0xFF, 0x00, 0x00, 0xBF }; + constexpr uint8_t openBusBits[5] = {0xFF, 0xFF, 0x00, 0x00, 0xBF}; uint8_t value = 0; - switch(addr) { - case 2: - value = ( - (_state.EnvVolume << 4) | - (_state.EnvRaiseVolume ? 0x08 : 0) | - _state.EnvPeriod - ); - break; + switch (addr) + { + case 2: + value = ( + (_state.EnvVolume << 4) | + (_state.EnvRaiseVolume ? 0x08 : 0) | + _state.EnvPeriod + ); + break; - case 3: - value = ( - (_state.PeriodShift << 4) | - (_state.ShortWidthMode ? 0x08 : 0) | - _state.Divisor - ); - break; + case 3: + value = ( + (_state.PeriodShift << 4) | + (_state.ShortWidthMode ? 0x08 : 0) | + _state.Divisor + ); + break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -128,30 +146,34 @@ uint8_t GbNoiseChannel::Read(uint16_t addr) void GbNoiseChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: break; - case 1: - _state.Length = 64 - (value & 0x3F); - break; + switch (addr) + { + case 0: break; + case 1: + _state.Length = 64 - (value & 0x3F); + break; - case 2: - _state.EnvPeriod = value & 0x07; - _state.EnvRaiseVolume = (value & 0x08) != 0; - _state.EnvVolume = (value & 0xF0) >> 4; + case 2: + _state.EnvPeriod = value & 0x07; + _state.EnvRaiseVolume = (value & 0x08) != 0; + _state.EnvVolume = (value & 0xF0) >> 4; - if(!(value & 0xF8)) { - _state.Enabled = false; - } - break; + if (!(value & 0xF8)) + { + _state.Enabled = false; + } + break; - case 3: - _state.PeriodShift = (value & 0xF0) >> 4; - _state.ShortWidthMode = (value & 0x08) != 0; - _state.Divisor = value & 0x07; - break; + case 3: + _state.PeriodShift = (value & 0xF0) >> 4; + _state.ShortWidthMode = (value & 0x08) != 0; + _state.Divisor = value & 0x07; + break; - case 4: { - if(value & 0x80) { + case 4: + { + if (value & 0x80) + { //Writing a value to NRx4 with bit 7 set causes the following things to occur : //Channel is enabled, if volume is not 0 or raise volume flag is set @@ -164,7 +186,8 @@ void GbNoiseChannel::Write(uint16_t addr, uint8_t value) _state.ShiftRegister = 0x7FFF; //If length counter is zero, it is set to 64 (256 for wave channel). - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 64; _state.LengthEnabled = false; } diff --git a/Core/GbNoiseChannel.h b/Core/GbNoiseChannel.h index e5073e5..08cc37a 100644 --- a/Core/GbNoiseChannel.h +++ b/Core/GbNoiseChannel.h @@ -31,4 +31,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index bcdb4df..283885c 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -15,9 +15,10 @@ #include "../Utilities/HexUtilities.h" #include "../Utilities/Serializer.h" -constexpr uint16_t evtColors[6] = { 0x18C6, 0x294A, 0x108C, 0x4210, 0x3084, 0x1184 }; +constexpr uint16_t evtColors[6] = {0x18C6, 0x294A, 0x108C, 0x4210, 0x3084, 0x1184}; -void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, uint8_t* vram, uint8_t* oam) +void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, + uint8_t* vram, uint8_t* oam) { _console = console; _gameboy = gameboy; @@ -76,10 +77,12 @@ uint16_t* GbPpu::GetPreviousEventViewerBuffer() void GbPpu::Exec() { - if(!_state.LcdEnabled) { + if (!_state.LcdEnabled) + { //LCD is disabled, prevent IRQs, etc. //Not quite correct in terms of frame pacing - if(_gameboy->GetApuCycleCount() - _lastFrameTime > 70224) { + if (_gameboy->GetApuCycleCount() - _lastFrameTime > 70224) + { //More than a full frame's worth of time has passed since the last frame, send another blank frame _lastFrameTime = _gameboy->GetApuCycleCount(); SendFrame(); @@ -88,9 +91,11 @@ void GbPpu::Exec() } uint8_t cyclesToRun = _memoryManager->IsHighSpeed() ? 1 : 2; - for(int i = 0; i < cyclesToRun; i++) { + for (int i = 0; i < cyclesToRun; i++) + { _state.Cycle++; - if(_state.IdleCycles > 0) { + if (_state.IdleCycles > 0) + { _state.IdleCycles--; ProcessPpuCycle(); continue; @@ -104,32 +109,44 @@ void GbPpu::ExecCycle() { PpuMode oldMode = _state.IrqMode; - if(_state.Scanline < 144) { - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline < 144) + { + if (_state.Scanline == 0 && _isFirstFrame) + { ProcessFirstScanlineAfterPowerOn(); - } else { + } + else + { ProcessVisibleScanline(); } - } else { + } + else + { ProcessVblankScanline(); } - if(_state.Mode == PpuMode::Drawing) { + if (_state.Mode == PpuMode::Drawing) + { RunDrawCycle(); - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //Mode turns to hblank on the same cycle as the last pixel is output (IRQ is on next cycle) _state.Mode = PpuMode::HBlank; - if(_state.Scanline < 143) { + if (_state.Scanline < 143) + { //"This mode will transfer one block (16 bytes) during each H-Blank. No data is transferred during VBlank (LY = 143 – 153)" _dmaController->ProcessHdma(); } } - } else if(_state.Mode == PpuMode::OamEvaluation) { + } + else if (_state.Mode == PpuMode::OamEvaluation) + { RunSpriteEvaluation(); } bool coincidenceFlag = (_state.LyCompare == _state.LyForCompare); - if(_state.IrqMode != oldMode || _state.LyCoincidenceFlag != coincidenceFlag) { + if (_state.IrqMode != oldMode || _state.LyCoincidenceFlag != coincidenceFlag) + { _state.LyCoincidenceFlag = coincidenceFlag; UpdateStatIrq(); } @@ -139,176 +156,203 @@ void GbPpu::ExecCycle() void GbPpu::ProcessVblankScanline() { - switch(_state.Cycle) { - case 2: - if(_state.Scanline == 144) { - _state.IrqMode = PpuMode::OamEvaluation; + switch (_state.Cycle) + { + case 2: + if (_state.Scanline == 144) + { + _state.IrqMode = PpuMode::OamEvaluation; + } + break; + + case 4: + if (_state.Scanline < 153) + { + _state.LyForCompare = _state.Scanline; + if (_state.Scanline == 144) + { + _state.Mode = PpuMode::VBlank; + _state.IrqMode = PpuMode::VBlank; + _windowCounter = -1; + _memoryManager->RequestIrq(GbIrqSource::VerticalBlank); + SendFrame(); } - break; + } + break; - case 4: - if(_state.Scanline < 153) { - _state.LyForCompare = _state.Scanline; - if(_state.Scanline == 144) { - _state.Mode = PpuMode::VBlank; - _state.IrqMode = PpuMode::VBlank; - _windowCounter = -1; - _memoryManager->RequestIrq(GbIrqSource::VerticalBlank); - SendFrame(); - } + case 6: + if (_state.Scanline == 153) + { + _state.Ly = 0; + _state.LyForCompare = _state.Scanline; + } + break; + + case 8: + if (_state.Scanline == 153) + { + _state.LyForCompare = -1; + } + break; + + case 12: + if (_state.Scanline == 153) + { + _state.LyForCompare = 0; + } + _state.IdleCycles = 456 - 12 - 1; + break; + + case 456: + _state.Cycle = 0; + _state.Scanline++; + + if (_state.Scanline == 154) + { + _state.Scanline = 0; + _state.Ly = 0; + _state.LyForCompare = 0; + + if (_console->IsDebugging()) + { + _console->ProcessEvent(EventType::GbStartFrame); + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] + ? _eventViewerBuffers[1] + : _eventViewerBuffers[0]; } - break; - - case 6: - if(_state.Scanline == 153) { - _state.Ly = 0; - _state.LyForCompare = _state.Scanline; - } - break; - - case 8: - if(_state.Scanline == 153) { - _state.LyForCompare = -1; - } - break; - - case 12: - if(_state.Scanline == 153) { - _state.LyForCompare = 0; - } - _state.IdleCycles = 456 - 12 - 1; - break; - - case 456: - _state.Cycle = 0; - _state.Scanline++; - - if(_state.Scanline == 154) { - _state.Scanline = 0; - _state.Ly = 0; - _state.LyForCompare = 0; - - if(_console->IsDebugging()) { - _console->ProcessEvent(EventType::GbStartFrame); - _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; - } - } else { - _state.Ly = _state.Scanline; - _state.LyForCompare = -1; - } - break; + } + else + { + _state.Ly = _state.Scanline; + _state.LyForCompare = -1; + } + break; } } void GbPpu::ProcessFirstScanlineAfterPowerOn() { - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //IRQ flag for Hblank is 1 cycle late compared to the mode register _state.IrqMode = PpuMode::HBlank; _drawnPixels = 0; _state.IdleCycles = 448 - _state.Cycle - 1; } - switch(_state.Cycle) { - case 1: - _state.IrqMode = PpuMode::NoIrq; - break; + switch (_state.Cycle) + { + case 1: + _state.IrqMode = PpuMode::NoIrq; + break; - case 79: - _latchWindowX = _state.WindowX; - _latchWindowY = _state.WindowY; - _latchWindowEnabled = _state.WindowEnabled; - _state.Mode = PpuMode::Drawing; - _state.IrqMode = PpuMode::Drawing; - ResetRenderer(); - _rendererIdle = true; - break; + case 79: + _latchWindowX = _state.WindowX; + _latchWindowY = _state.WindowY; + _latchWindowEnabled = _state.WindowEnabled; + _state.Mode = PpuMode::Drawing; + _state.IrqMode = PpuMode::Drawing; + ResetRenderer(); + _rendererIdle = true; + break; - case 84: - _rendererIdle = false; - break; + case 84: + _rendererIdle = false; + break; - case 448: - _state.Cycle = 0; - _state.Scanline++; - _drawnPixels = 0; - _state.Mode = PpuMode::HBlank; - _state.IrqMode = PpuMode::HBlank; - break; + case 448: + _state.Cycle = 0; + _state.Scanline++; + _drawnPixels = 0; + _state.Mode = PpuMode::HBlank; + _state.IrqMode = PpuMode::HBlank; + break; } } void GbPpu::ProcessVisibleScanline() { - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //IRQ flag for Hblank is 1 cycle late compared to the mode register _state.IrqMode = PpuMode::HBlank; _drawnPixels = 0; _state.IdleCycles = 456 - _state.Cycle - 1; } - switch(_state.Cycle) { - case 3: - _state.Ly = _state.Scanline; + switch (_state.Cycle) + { + case 3: + _state.Ly = _state.Scanline; - if(_state.Scanline > 0) { - //On scanlines 1-143, the OAM IRQ fires 1 cycle early - _state.IrqMode = PpuMode::OamEvaluation; - _state.LyForCompare = -1; - } else { - //On scanline 0, hblank gets set for 1 cycle here - _state.Mode = PpuMode::HBlank; - } - break; - - case 4: - _spriteCount = 0; - _state.LyForCompare = _state.Scanline; - _state.Mode = PpuMode::OamEvaluation; + if (_state.Scanline > 0) + { + //On scanlines 1-143, the OAM IRQ fires 1 cycle early _state.IrqMode = PpuMode::OamEvaluation; - break; + _state.LyForCompare = -1; + } + else + { + //On scanline 0, hblank gets set for 1 cycle here + _state.Mode = PpuMode::HBlank; + } + break; - case 5: - //Turning on OAM IRQs in the middle of evaluation has no effect? - //Or is this a patch to get the proper behavior for the STAT write bug? - _state.IrqMode = PpuMode::NoIrq; - break; + case 4: + _spriteCount = 0; + _state.LyForCompare = _state.Scanline; + _state.Mode = PpuMode::OamEvaluation; + _state.IrqMode = PpuMode::OamEvaluation; + break; - case 84: - _latchWindowX = _state.WindowX; - _latchWindowY = _state.WindowY; - _latchWindowEnabled = _state.WindowEnabled; - _state.Mode = PpuMode::Drawing; - _state.IrqMode = PpuMode::Drawing; - _rendererIdle = true; - ResetRenderer(); - break; + case 5: + //Turning on OAM IRQs in the middle of evaluation has no effect? + //Or is this a patch to get the proper behavior for the STAT write bug? + _state.IrqMode = PpuMode::NoIrq; + break; - case 89: - _rendererIdle = false; - break; + case 84: + _latchWindowX = _state.WindowX; + _latchWindowY = _state.WindowY; + _latchWindowEnabled = _state.WindowEnabled; + _state.Mode = PpuMode::Drawing; + _state.IrqMode = PpuMode::Drawing; + _rendererIdle = true; + ResetRenderer(); + break; - case 456: - _state.Cycle = 0; - _state.Scanline++; - if(_state.Scanline == 144) { - _state.Ly = 144; - _state.LyForCompare = -1; - } - break; + case 89: + _rendererIdle = false; + break; + + case 456: + _state.Cycle = 0; + _state.Scanline++; + if (_state.Scanline == 144) + { + _state.Ly = 144; + _state.LyForCompare = -1; + } + break; } } void GbPpu::ProcessPpuCycle() { - if(_console->IsDebugging()) { + if (_console->IsDebugging()) + { _console->ProcessPpuCycle(); - if(_state.Mode <= PpuMode::OamEvaluation) { + if (_state.Mode <= PpuMode::OamEvaluation) + { _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = evtColors[(int)_state.Mode]; - } else if(_prevDrawnPixels != _drawnPixels && _drawnPixels > 0) { + } + else if (_prevDrawnPixels != _drawnPixels && _drawnPixels > 0) + { uint16_t color = _currentBuffer[_state.Scanline * 256 + (_drawnPixels - 1)]; _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = color; - } else { + } + else + { _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = evtColors[(int)_evtColor]; } _prevDrawnPixels = _drawnPixels; @@ -317,14 +361,16 @@ void GbPpu::ProcessPpuCycle() void GbPpu::RunDrawCycle() { - if(_rendererIdle) { + if (_rendererIdle) + { //Idle cycles _evtColor = EvtColor::RenderingIdle; return; } bool fetchWindow = _latchWindowEnabled && _drawnPixels >= _latchWindowX - 7 && _state.Scanline >= _latchWindowY; - if(_fetchWindow != fetchWindow) { + if (_fetchWindow != fetchWindow) + { //Switched between window & background, reset fetcher & pixel FIFO _fetchWindow = fetchWindow; _fetchColumn = 0; @@ -339,39 +385,55 @@ void GbPpu::RunDrawCycle() } FindNextSprite(); - if(_fetchSprite >= 0 && _bgFetcher.Step >= 5 && _bgFifo.Size > 0) { + if (_fetchSprite >= 0 && _bgFetcher.Step >= 5 && _bgFifo.Size > 0) + { _evtColor = EvtColor::RenderingOamLoad; ClockSpriteFetcher(); FindNextSprite(); return; } - if(_fetchSprite == -1 && _bgFifo.Size > 0) { - if(_drawnPixels >= 0) { + if (_fetchSprite == -1 && _bgFifo.Size > 0) + { + if (_drawnPixels >= 0) + { uint16_t outOffset = _state.Scanline * 256 + _drawnPixels; GbFifoEntry entry = _bgFifo.Content[_bgFifo.Position]; GbFifoEntry sprite = _oamFifo.Content[_oamFifo.Position]; - if(sprite.Color != 0 && (entry.Color == 0 || (!(sprite.Attributes & 0x80) && !(entry.Attributes & 0x80)) || (_state.CgbEnabled && !_state.BgEnabled))) { + if (sprite.Color != 0 && (entry.Color == 0 || (!(sprite.Attributes & 0x80) && !(entry.Attributes & 0x80)) || ( + _state.CgbEnabled && !_state.BgEnabled))) + { //Use sprite pixel if: // -BG color is 0, OR // -Sprite is background priority AND BG does not have its priority bit set, OR // -On CGB, the "bg enabled" flag is cleared, causing all sprites to appear above BG tiles - if(_state.CgbEnabled) { + if (_state.CgbEnabled) + { _currentBuffer[outOffset] = _state.CgbObjPalettes[sprite.Color | ((sprite.Attributes & 0x07) << 2)]; - } else { - uint8_t colorIndex = (((sprite.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (sprite.Color * 2)) & 0x03; - if(_gameboy->IsSgb()) { + } + else + { + uint8_t colorIndex = (((sprite.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (sprite. + Color * 2)) & 0x03; + if (_gameboy->IsSgb()) + { _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); - } + } _currentBuffer[outOffset] = _state.CgbObjPalettes[((sprite.Attributes & 0x10) ? 4 : 0) | colorIndex]; } - } else { - if(_state.CgbEnabled) { + } + else + { + if (_state.CgbEnabled) + { _currentBuffer[outOffset] = _state.CgbBgPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)]; - } else { + } + else + { uint8_t colorIndex = (_state.BgPalette >> (entry.Color * 2)) & 0x03; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); } _currentBuffer[outOffset] = _state.CgbBgPalettes[colorIndex]; @@ -382,7 +444,8 @@ void GbPpu::RunDrawCycle() _bgFifo.Pop(); _drawnPixels++; - if(_oamFifo.Size > 0) { + if (_oamFifo.Size > 0) + { _oamFifo.Pop(); } } @@ -392,23 +455,28 @@ void GbPpu::RunDrawCycle() void GbPpu::RunSpriteEvaluation() { - if(_state.Cycle & 0x01) { - if(_spriteCount < 10) { + if (_state.Cycle & 0x01) + { + if (_spriteCount < 10) + { uint8_t spriteIndex = ((_state.Cycle - 4) >> 1) * 4; int16_t sprY = _dmaController->IsOamDmaRunning() ? 0xFF : ((int16_t)_oam[spriteIndex] - 16); - if(_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) { + if (_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) + { _spriteX[_spriteCount] = _oam[spriteIndex + 1]; _spriteIndexes[_spriteCount] = spriteIndex; _spriteCount++; } } - } else { + } + else + { //TODO check proper timing for even&odd cycles } } void GbPpu::ResetRenderer() -{ +{ //Reset fetcher & pixel FIFO _oamFifo.Reset(); _oamFetcher.Step = 0; @@ -425,8 +493,10 @@ void GbPpu::ResetRenderer() void GbPpu::ClockSpriteFetcher() { - switch(_oamFetcher.Step++) { - case 1: { + switch (_oamFetcher.Step++) + { + case 1: + { //Fetch tile index int16_t sprY = (int16_t)_oam[_fetchSprite] - 16; uint8_t sprTile = _oam[_fetchSprite + 2]; @@ -434,8 +504,11 @@ void GbPpu::ClockSpriteFetcher() bool vMirror = (sprAttr & 0x40) != 0; uint16_t tileBank = _state.CgbEnabled ? ((sprAttr & 0x08) ? 0x2000 : 0x0000) : 0; - uint8_t sprOffsetY = vMirror ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) : (_state.Scanline - sprY); - if(_state.LargeSprites) { + uint8_t sprOffsetY = vMirror + ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) + : (_state.Scanline - sprY); + if (_state.LargeSprites) + { sprTile &= 0xFE; } @@ -445,9 +518,11 @@ void GbPpu::ClockSpriteFetcher() break; } - case 3: _oamFetcher.LowByte = _vram[_oamFetcher.Addr]; break; + case 3: _oamFetcher.LowByte = _vram[_oamFetcher.Addr]; + break; - case 5: { + case 5: + { //Fetch sprite data (high byte) _oamFetcher.HighByte = _vram[_oamFetcher.Addr + 1]; PushSpriteToPixelFifo(); @@ -458,9 +533,12 @@ void GbPpu::ClockSpriteFetcher() void GbPpu::FindNextSprite() { - if(_fetchSprite < 0 && (_state.SpritesEnabled || _state.CgbEnabled)) { - for(int i = 0; i < _spriteCount; i++) { - if((int)_spriteX[i] - 8 == _drawnPixels) { + if (_fetchSprite < 0 && (_state.SpritesEnabled || _state.CgbEnabled)) + { + for (int i = 0; i < _spriteCount; i++) + { + if ((int)_spriteX[i] - 8 == _drawnPixels) + { _fetchSprite = _spriteIndexes[i]; _spriteX[i] = 0xFF; //Prevent processing the same sprite again _oamFetcher.Step = 0; @@ -474,15 +552,20 @@ void GbPpu::ClockTileFetcher() { _evtColor = EvtColor::RenderingBgLoad; - switch(_bgFetcher.Step++) { - case 1: { + switch (_bgFetcher.Step++) + { + case 1: + { //Fetch tile index uint16_t tilemapAddr; uint8_t yOffset; - if(_fetchWindow) { + if (_fetchWindow) + { tilemapAddr = _state.WindowTilemapSelect ? 0x1C00 : 0x1800; yOffset = (uint8_t)_windowCounter; - } else { + } + else + { tilemapAddr = _state.BgTilemapSelect ? 0x1C00 : 0x1800; yOffset = _state.ScrollY + _state.Scanline; } @@ -504,28 +587,33 @@ void GbPpu::ClockTileFetcher() break; } - case 3: { + case 3: + { //Fetch tile data (low byte) _bgFetcher.LowByte = _vram[_bgFetcher.Addr]; break; } - case 5: { + case 5: + { //Fetch tile data (high byte) _bgFetcher.HighByte = _vram[_bgFetcher.Addr + 1]; - + //Fallthrough } - case 6: - case 7: - if(_bgFifo.Size == 0) { - PushTileToPixelFifo(); - } else if(_bgFetcher.Step == 8) { - //Wait until fifo is empty to push pixels - _bgFetcher.Step = 7; - } - break; + case 6: + case 7: + if (_bgFifo.Size == 0) + { + PushTileToPixelFifo(); + } + else if (_bgFetcher.Step == 8) + { + //Wait until fifo is empty to push pixels + _bgFetcher.Step = 7; + } + break; } } @@ -534,19 +622,22 @@ void GbPpu::PushSpriteToPixelFifo() _fetchSprite = -1; _oamFetcher.Step = 0; - if(!_state.SpritesEnabled) { + if (!_state.SpritesEnabled) + { return; } uint8_t pos = _oamFifo.Position; //Overlap sprite - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { uint8_t shift = (_oamFetcher.Attributes & 0x20) ? i : (7 - i); uint8_t bits = ((_oamFetcher.LowByte >> shift) & 0x01); bits |= ((_oamFetcher.HighByte >> shift) & 0x01) << 1; - if(bits > 0 && _oamFifo.Content[pos].Color == 0) { + if (bits > 0 && _oamFifo.Content[pos].Color == 0) + { _oamFifo.Content[pos].Color = bits; _oamFifo.Content[pos].Attributes = _oamFetcher.Attributes; } @@ -558,7 +649,8 @@ void GbPpu::PushSpriteToPixelFifo() void GbPpu::PushTileToPixelFifo() { //Add new tile to fifo - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { uint8_t shift = (_bgFetcher.Attributes & 0x20) ? i : (7 - i); uint8_t bits = ((_bgFetcher.LowByte >> shift) & 0x01); bits |= ((_bgFetcher.HighByte >> shift) & 0x01) << 1; @@ -578,12 +670,13 @@ void GbPpu::UpdateStatIrq() bool irqFlag = ( _state.LcdEnabled && ((_state.LyCoincidenceFlag && (_state.Status & GbPpuStatusFlags::CoincidenceIrq)) || - (_state.IrqMode == PpuMode::HBlank && (_state.Status & GbPpuStatusFlags::HBlankIrq)) || - (_state.IrqMode == PpuMode::OamEvaluation && (_state.Status & GbPpuStatusFlags::OamIrq)) || - (_state.IrqMode == PpuMode::VBlank && (_state.Status & GbPpuStatusFlags::VBlankIrq))) + (_state.IrqMode == PpuMode::HBlank && (_state.Status & GbPpuStatusFlags::HBlankIrq)) || + (_state.IrqMode == PpuMode::OamEvaluation && (_state.Status & GbPpuStatusFlags::OamIrq)) || + (_state.IrqMode == PpuMode::VBlank && (_state.Status & GbPpuStatusFlags::VBlankIrq))) ); - if(irqFlag && !_state.StatIrqFlag) { + if (irqFlag && !_state.StatIrqFlag) + { _memoryManager->RequestIrq(GbIrqSource::LcdStat); } _state.StatIrqFlag = irqFlag; @@ -624,7 +717,8 @@ void GbPpu::SendFrame() _console->ProcessEvent(EventType::GbEndFrame); _state.FrameCount++; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { return; } @@ -632,11 +726,15 @@ void GbPpu::SendFrame() _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone); - if(_isFirstFrame) { - if(!_state.CgbEnabled) { + if (_isFirstFrame) + { + if (!_state.CgbEnabled) + { //Send blank frame on the first frame after enabling LCD (DMG only) std::fill(_currentBuffer, _currentBuffer + 256 * 239, 0x7FFF); - } else { + } + else + { //CGB repeats the previous frame? uint16_t* src = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; std::copy(src, src + 256 * 239, _currentBuffer); @@ -647,9 +745,12 @@ void GbPpu::SendFrame() #ifdef LIBRETRO _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, 256, 239, _state.FrameCount, false); #else - if(_console->GetRewindManager()->IsRewinding()) { + if (_console->GetRewindManager()->IsRewinding()) + { _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, 256, 239, _state.FrameCount, true); - } else { + } + else + { _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, 256, 239, _state.FrameCount); } #endif @@ -658,7 +759,8 @@ void GbPpu::SendFrame() uint8_t prevInput = _memoryManager->ReadInputPort(); _console->ProcessEndOfFrame(); uint8_t newInput = _memoryManager->ReadInputPort(); - if(prevInput != newInput) { + if (prevInput != newInput) + { _memoryManager->RequestIrq(GbIrqSource::Joypad); } @@ -667,17 +769,22 @@ void GbPpu::SendFrame() void GbPpu::UpdatePalette() { - if(!_gameboy->IsCgb()) { + if (!_gameboy->IsCgb()) + { GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig(); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { //Set palette based on settings (DMG) - uint16_t bgColor = ((cfg.BgColors[i] & 0xF8) << 7) | ((cfg.BgColors[i] & 0xF800) >> 6) | ((cfg.BgColors[i] & 0xF80000) >> 19); + uint16_t bgColor = ((cfg.BgColors[i] & 0xF8) << 7) | ((cfg.BgColors[i] & 0xF800) >> 6) | ((cfg.BgColors[i] & + 0xF80000) >> 19); _state.CgbBgPalettes[i] = bgColor; - uint16_t obj0Color = ((cfg.Obj0Colors[i] & 0xF8) << 7) | ((cfg.Obj0Colors[i] & 0xF800) >> 6) | ((cfg.Obj0Colors[i] & 0xF80000) >> 19); + uint16_t obj0Color = ((cfg.Obj0Colors[i] & 0xF8) << 7) | ((cfg.Obj0Colors[i] & 0xF800) >> 6) | ((cfg.Obj0Colors + [i] & 0xF80000) >> 19); _state.CgbObjPalettes[i] = obj0Color; - - uint16_t obj1Color = ((cfg.Obj1Colors[i] & 0xF8) << 7) | ((cfg.Obj1Colors[i] & 0xF800) >> 6) | ((cfg.Obj1Colors[i] & 0xF80000) >> 19); + + uint16_t obj1Color = ((cfg.Obj1Colors[i] & 0xF8) << 7) | ((cfg.Obj1Colors[i] & 0xF800) >> 6) | ((cfg.Obj1Colors + [i] & 0xF80000) >> 19); _state.CgbObjPalettes[i + 4] = obj1Color; } } @@ -685,116 +792,136 @@ void GbPpu::UpdatePalette() uint8_t GbPpu::Read(uint16_t addr) { - switch(addr) { - case 0xFF40: return _state.Control; - case 0xFF41: - //FF41 - STAT - LCDC Status (R/W) - return ( - 0x80 | - (_state.Status & 0x78) | - (_state.LyCoincidenceFlag ? 0x04 : 0x00) | - (int)_state.Mode - ); + switch (addr) + { + case 0xFF40: return _state.Control; + case 0xFF41: + //FF41 - STAT - LCDC Status (R/W) + return ( + 0x80 | + (_state.Status & 0x78) | + (_state.LyCoincidenceFlag ? 0x04 : 0x00) | + (int)_state.Mode + ); - case 0xFF42: return _state.ScrollY; //FF42 - SCY - Scroll Y (R/W) - case 0xFF43: return _state.ScrollX; //FF43 - SCX - Scroll X (R/W) - case 0xFF44: return _state.Ly; //FF44 - LY - LCDC Y-Coordinate (R) - case 0xFF45: return _state.LyCompare; //FF45 - LYC - LY Compare (R/W) - case 0xFF47: return _state.BgPalette; //FF47 - BGP - BG Palette Data (R/W) - Non CGB Mode Only - case 0xFF48: return _state.ObjPalette0; //FF48 - OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only - case 0xFF49: return _state.ObjPalette1; //FF49 - OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only - case 0xFF4A: return _state.WindowY; //FF4A - WY - Window Y Position (R/W) - case 0xFF4B: return _state.WindowX; //FF4B - WX - Window X Position minus 7 (R/W) + case 0xFF42: return _state.ScrollY; //FF42 - SCY - Scroll Y (R/W) + case 0xFF43: return _state.ScrollX; //FF43 - SCX - Scroll X (R/W) + case 0xFF44: return _state.Ly; //FF44 - LY - LCDC Y-Coordinate (R) + case 0xFF45: return _state.LyCompare; //FF45 - LYC - LY Compare (R/W) + case 0xFF47: return _state.BgPalette; //FF47 - BGP - BG Palette Data (R/W) - Non CGB Mode Only + case 0xFF48: return _state.ObjPalette0; //FF48 - OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only + case 0xFF49: return _state.ObjPalette1; //FF49 - OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only + case 0xFF4A: return _state.WindowY; //FF4A - WY - Window Y Position (R/W) + case 0xFF4B: return _state.WindowX; //FF4B - WX - Window X Position minus 7 (R/W) } - + LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; } void GbPpu::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF40: - _state.Control = value; - if(_state.LcdEnabled != ((value & 0x80) != 0)) { - _state.LcdEnabled = (value & 0x80) != 0; - - if(!_state.LcdEnabled) { - //Reset LCD to top of screen when it gets turned off - if(_state.Mode != PpuMode::VBlank) { - _console->BreakImmediately(BreakSource::GbDisableLcdOutsideVblank); - SendFrame(); - } + switch (addr) + { + case 0xFF40: + _state.Control = value; + if (_state.LcdEnabled != ((value & 0x80) != 0)) + { + _state.LcdEnabled = (value & 0x80) != 0; - _state.Cycle = 0; - _state.Scanline = 0; - _state.Ly = 0; - _state.LyForCompare = 0; - _state.Mode = PpuMode::HBlank; + if (!_state.LcdEnabled) + { + //Reset LCD to top of screen when it gets turned off + if (_state.Mode != PpuMode::VBlank) + { + _console->BreakImmediately(BreakSource::GbDisableLcdOutsideVblank); + SendFrame(); + } - _lastFrameTime = _gameboy->GetApuCycleCount(); - - //"If the HDMA started when the screen was on, when the screen is switched off it will copy one block after the switch." - _dmaController->ProcessHdma(); - } else { - _isFirstFrame = true; - _state.Cycle = -1; - _state.IdleCycles = 0; - ResetRenderer(); - _state.LyCoincidenceFlag = _state.LyCompare == _state.LyForCompare; - UpdateStatIrq(); - - if(_console->IsDebugging()) { - _console->ProcessEvent(EventType::GbStartFrame); + _state.Cycle = 0; + _state.Scanline = 0; + _state.Ly = 0; + _state.LyForCompare = 0; + _state.Mode = PpuMode::HBlank; - _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; - for(int i = 0; i < 456 * 154; i++) { - _currentEventViewerBuffer[i] = 0x18C6; - } + _lastFrameTime = _gameboy->GetApuCycleCount(); + + //"If the HDMA started when the screen was on, when the screen is switched off it will copy one block after the switch." + _dmaController->ProcessHdma(); + } + else + { + _isFirstFrame = true; + _state.Cycle = -1; + _state.IdleCycles = 0; + ResetRenderer(); + _state.LyCoincidenceFlag = _state.LyCompare == _state.LyForCompare; + UpdateStatIrq(); + + if (_console->IsDebugging()) + { + _console->ProcessEvent(EventType::GbStartFrame); + + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] + ? _eventViewerBuffers[1] + : _eventViewerBuffers[0]; + for (int i = 0; i < 456 * 154; i++) + { + _currentEventViewerBuffer[i] = 0x18C6; } } } - _state.WindowTilemapSelect = (value & 0x40) != 0; - _state.WindowEnabled = (value & 0x20) != 0; - _state.BgTileSelect = (value & 0x10) != 0; - _state.BgTilemapSelect = (value & 0x08) != 0; - _state.LargeSprites = (value & 0x04) != 0; - _state.SpritesEnabled = (value & 0x02) != 0; - _state.BgEnabled = (value & 0x01) != 0; - break; + } + _state.WindowTilemapSelect = (value & 0x40) != 0; + _state.WindowEnabled = (value & 0x20) != 0; + _state.BgTileSelect = (value & 0x10) != 0; + _state.BgTilemapSelect = (value & 0x08) != 0; + _state.LargeSprites = (value & 0x04) != 0; + _state.SpritesEnabled = (value & 0x02) != 0; + _state.BgEnabled = (value & 0x01) != 0; + break; - case 0xFF41: - if(!_gameboy->IsCgb()) { - //STAT write bug (DMG ONLY) - //Writing to STAT causes all IRQ types to be turned on for a single cycle - _state.Status = 0xF8 | (_state.Status & 0x07); - UpdateStatIrq(); - } - - _state.Status = value & 0xF8; + case 0xFF41: + if (!_gameboy->IsCgb()) + { + //STAT write bug (DMG ONLY) + //Writing to STAT causes all IRQ types to be turned on for a single cycle + _state.Status = 0xF8 | (_state.Status & 0x07); UpdateStatIrq(); - break; + } - case 0xFF42: _state.ScrollY = value; break; - case 0xFF43: _state.ScrollX = value; break; - case 0xFF45: - _state.LyCompare = value; - if(_state.LcdEnabled) { - _state.IdleCycles = 0; - _state.LyCoincidenceFlag = (_state.LyCompare == _state.LyForCompare); - UpdateStatIrq(); - } - break; + _state.Status = value & 0xF8; + UpdateStatIrq(); + break; - case 0xFF47: _state.BgPalette = value; break; - case 0xFF48: _state.ObjPalette0 = value; break; - case 0xFF49: _state.ObjPalette1 = value; break; - case 0xFF4A: _state.WindowY = value; break; - case 0xFF4B: _state.WindowX = value; break; + case 0xFF42: _state.ScrollY = value; + break; + case 0xFF43: _state.ScrollX = value; + break; + case 0xFF45: + _state.LyCompare = value; + if (_state.LcdEnabled) + { + _state.IdleCycles = 0; + _state.LyCoincidenceFlag = (_state.LyCompare == _state.LyForCompare); + UpdateStatIrq(); + } + break; - default: - LogDebug("[Debug] GB - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; + case 0xFF47: _state.BgPalette = value; + break; + case 0xFF48: _state.ObjPalette0 = value; + break; + case 0xFF49: _state.ObjPalette1 = value; + break; + case 0xFF4A: _state.WindowY = value; + break; + case 0xFF4B: _state.WindowX = value; + break; + + default: + LogDebug("[Debug] GB - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; } } @@ -810,11 +937,14 @@ bool GbPpu::IsVramWriteAllowed() uint8_t GbPpu::ReadVram(uint16_t addr) { - if(IsVramReadAllowed()) { + if (IsVramReadAllowed()) + { uint16_t vramAddr = (_state.CgbVramBank << 13) | (addr & 0x1FFF); _console->ProcessPpuRead(vramAddr, _vram[vramAddr], SnesMemoryType::GbVideoRam); return _vram[vramAddr]; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidVramAccess); return 0xFF; } @@ -827,44 +957,56 @@ uint8_t GbPpu::PeekVram(uint16_t addr) void GbPpu::WriteVram(uint16_t addr, uint8_t value) { - if(IsVramWriteAllowed()) { + if (IsVramWriteAllowed()) + { uint16_t vramAddr = (_state.CgbVramBank << 13) | (addr & 0x1FFF); _console->ProcessPpuWrite(vramAddr, value, SnesMemoryType::GbVideoRam); _vram[vramAddr] = value; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidVramAccess); } } bool GbPpu::IsOamWriteAllowed() { - if(_memoryManager->IsOamDmaRunning()) { + if (_memoryManager->IsOamDmaRunning()) + { return false; } - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline == 0 && _isFirstFrame) + { return _state.Mode == PpuMode::HBlank && _state.Cycle != 77 && _state.Cycle != 78; - } else { + } + else + { return _state.Mode <= PpuMode::VBlank || (_state.Cycle >= 80 && _state.Cycle < 84); } } bool GbPpu::IsOamReadAllowed() { - if(_memoryManager->IsOamDmaRunning()) { + if (_memoryManager->IsOamDmaRunning()) + { return false; } - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline == 0 && _isFirstFrame) + { return _state.Mode == PpuMode::HBlank; - } else { + } + else + { return _state.Mode == PpuMode::VBlank || (_state.Mode == PpuMode::HBlank && _state.Cycle != 3); } } uint8_t GbPpu::PeekOam(uint8_t addr) { - if(addr < 0xA0) { + if (addr < 0xA0) + { return IsOamReadAllowed() ? _oam[addr] : 0xFF; } return 0; @@ -872,11 +1014,15 @@ uint8_t GbPpu::PeekOam(uint8_t addr) uint8_t GbPpu::ReadOam(uint8_t addr) { - if(addr < 0xA0) { - if(IsOamReadAllowed()) { + if (addr < 0xA0) + { + if (IsOamReadAllowed()) + { _console->ProcessPpuRead(addr, _oam[addr], SnesMemoryType::GbSpriteRam); return _oam[addr]; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidOamAccess); return 0xFF; } @@ -889,14 +1035,20 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma) //During DMA or rendering/oam evaluation, ignore writes to OAM //The DMA controller is always allowed to write to OAM (presumably the PPU can't read OAM during that time? TODO implement) //On the DMG, there is a 4 clock gap (80 to 83) between OAM evaluation & rendering where writing is allowed - if(addr < 0xA0) { - if(forDma) { + if (addr < 0xA0) + { + if (forDma) + { _oam[addr] = value; _console->ProcessPpuWrite(addr, value, SnesMemoryType::GbSpriteRam); - } else if(IsOamWriteAllowed()) { + } + else if (IsOamWriteAllowed()) + { _oam[addr] = value; _console->ProcessPpuWrite(addr, value, SnesMemoryType::GbSpriteRam); - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidOamAccess); } } @@ -904,16 +1056,21 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma) uint8_t GbPpu::ReadCgbRegister(uint16_t addr) { - if(!_state.CgbEnabled) { + if (!_state.CgbEnabled) + { return 0xFF; } - switch(addr) { - case 0xFF4F: return _state.CgbVramBank | 0xFE; - case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0) | 0x40; - case 0xFF69: return (_state.CgbBgPalettes[_state.CgbBgPalPosition >> 1] >> ((_state.CgbBgPalPosition & 0x01) ? 8 : 0) & 0xFF); - case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0) | 0x40; - case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) ? 8 : 0) & 0xFF); + switch (addr) + { + case 0xFF4F: return _state.CgbVramBank | 0xFE; + case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0) | 0x40; + case 0xFF69: return (_state.CgbBgPalettes[_state.CgbBgPalPosition >> 1] >> ((_state.CgbBgPalPosition & 0x01) ? 8 : 0) + & 0xFF); + case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0) | 0x40; + case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) + ? 8 + : 0) & 0xFF); } LogDebug("[Debug] GBC - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; @@ -921,54 +1078,64 @@ uint8_t GbPpu::ReadCgbRegister(uint16_t addr) void GbPpu::WriteCgbRegister(uint16_t addr, uint8_t value) { - if(!_state.CgbEnabled && _memoryManager->IsBootRomDisabled()) { + if (!_state.CgbEnabled && _memoryManager->IsBootRomDisabled()) + { return; } - switch(addr) { - case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; break; - case 0xFF4F: _state.CgbVramBank = value & 0x01; break; - - case 0xFF68: - //FF68 - BCPS/BGPI - CGB Mode Only - Background Palette Index - _state.CgbBgPalPosition = value & 0x3F; - _state.CgbBgPalAutoInc = (value & 0x80) != 0; - break; + switch (addr) + { + case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; + break; + case 0xFF4F: _state.CgbVramBank = value & 0x01; + break; - case 0xFF69: { + case 0xFF68: + //FF68 - BCPS/BGPI - CGB Mode Only - Background Palette Index + _state.CgbBgPalPosition = value & 0x3F; + _state.CgbBgPalAutoInc = (value & 0x80) != 0; + break; + + case 0xFF69: + { //FF69 - BCPD/BGPD - CGB Mode Only - Background Palette Data WriteCgbPalette(_state.CgbBgPalPosition, _state.CgbBgPalettes, _state.CgbBgPalAutoInc, value); break; } - case 0xFF6A: - //FF6A - OCPS/OBPI - CGB Mode Only - Sprite Palette Index - _state.CgbObjPalPosition = value & 0x3F; - _state.CgbObjPalAutoInc = (value & 0x80) != 0; - break; + case 0xFF6A: + //FF6A - OCPS/OBPI - CGB Mode Only - Sprite Palette Index + _state.CgbObjPalPosition = value & 0x3F; + _state.CgbObjPalAutoInc = (value & 0x80) != 0; + break; - case 0xFF6B: - //FF6B - OCPD/OBPD - CGB Mode Only - Sprite Palette Data - WriteCgbPalette(_state.CgbObjPalPosition, _state.CgbObjPalettes, _state.CgbObjPalAutoInc, value); - break; + case 0xFF6B: + //FF6B - OCPD/OBPD - CGB Mode Only - Sprite Palette Data + WriteCgbPalette(_state.CgbObjPalPosition, _state.CgbObjPalettes, _state.CgbObjPalAutoInc, value); + break; - default: - LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; + default: + LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; } } void GbPpu::WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t value) { - if(_state.Mode <= PpuMode::OamEvaluation) { - if(pos & 0x01) { + if (_state.Mode <= PpuMode::OamEvaluation) + { + if (pos & 0x01) + { pal[pos >> 1] = (pal[pos >> 1] & 0xFF) | ((value & 0x7F) << 8); - } else { + } + else + { pal[pos >> 1] = (pal[pos >> 1] & 0xFF00) | value; } } - if(autoInc) { + if (autoInc) + { pos = (pos + 1) & 0x3F; } } @@ -976,9 +1143,12 @@ void GbPpu::WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t v void GbPpu::Serialize(Serializer& s) { s.Stream( - _state.Scanline, _state.Cycle, _state.Mode, _state.LyCompare, _state.BgPalette, _state.ObjPalette0, _state.ObjPalette1, - _state.ScrollX, _state.ScrollY, _state.WindowX, _state.WindowY, _state.Control, _state.LcdEnabled, _state.WindowTilemapSelect, - _state.WindowEnabled, _state.BgTileSelect, _state.BgTilemapSelect, _state.LargeSprites, _state.SpritesEnabled, _state.BgEnabled, + _state.Scanline, _state.Cycle, _state.Mode, _state.LyCompare, _state.BgPalette, _state.ObjPalette0, + _state.ObjPalette1, + _state.ScrollX, _state.ScrollY, _state.WindowX, _state.WindowY, _state.Control, _state.LcdEnabled, + _state.WindowTilemapSelect, + _state.WindowEnabled, _state.BgTileSelect, _state.BgTilemapSelect, _state.LargeSprites, _state.SpritesEnabled, + _state.BgEnabled, _state.Status, _state.FrameCount, _lastFrameTime, _state.LyCoincidenceFlag, _state.CgbBgPalAutoInc, _state.CgbBgPalPosition, _state.CgbObjPalAutoInc, _state.CgbObjPalPosition, _state.CgbVramBank, _state.CgbEnabled, @@ -996,7 +1166,8 @@ void GbPpu::Serialize(Serializer& s) _bgFifo.Position, _bgFifo.Size, _oamFifo.Position, _oamFifo.Size ); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { s.Stream(_bgFifo.Content[i].Color, _bgFifo.Content[i].Attributes); s.Stream(_oamFifo.Content[i].Color, _oamFifo.Content[i].Attributes); } diff --git a/Core/GbPpu.h b/Core/GbPpu.h index ff0415c..c541054 100644 --- a/Core/GbPpu.h +++ b/Core/GbPpu.h @@ -76,7 +76,8 @@ private: public: virtual ~GbPpu(); - void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, uint8_t* vram, uint8_t* oam); + void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, + uint8_t* vram, uint8_t* oam); GbPpuState GetState(); uint16_t* GetOutputBuffer(); @@ -109,6 +110,6 @@ public: uint8_t ReadCgbRegister(uint16_t addr); void WriteCgbRegister(uint16_t addr, uint8_t value); - + void Serialize(Serializer& s) override; }; diff --git a/Core/GbSquareChannel.cpp b/Core/GbSquareChannel.cpp index 8cbfa52..341b5a4 100644 --- a/Core/GbSquareChannel.cpp +++ b/Core/GbSquareChannel.cpp @@ -26,30 +26,37 @@ void GbSquareChannel::Disable() void GbSquareChannel::ClockSweepUnit() { - if(!_state.SweepEnabled) { + if (!_state.SweepEnabled) + { return; } - if(_state.SweepTimer > 0 && _state.SweepPeriod > 0) { + if (_state.SweepTimer > 0 && _state.SweepPeriod > 0) + { _state.SweepTimer--; - if(_state.SweepTimer == 0) { + if (_state.SweepTimer == 0) + { _state.SweepTimer = _state.SweepPeriod; //"When it generates a clock and the sweep's internal enabled flag is set and the sweep period is not zero, a new frequency is calculated and the overflow" uint16_t newFreq = GetSweepTargetFrequency(); - if(_state.SweepShift > 0 && newFreq < 2048) { + if (_state.SweepShift > 0 && newFreq < 2048) + { //"If the new frequency is 2047 or less and the sweep shift is not zero, this new frequency is written back to the shadow frequency and square 1's frequency in NR13 and NR14," _state.Frequency = _state.SweepFreq; _state.SweepFreq = newFreq; newFreq = GetSweepTargetFrequency(); - if(newFreq >= 2048) { + if (newFreq >= 2048) + { //"then frequency calculation and overflow check are run AGAIN immediately using this new value, but this second new frequency is not written back." _state.SweepEnabled = false; _state.Enabled = false; } - } else { + } + else + { _state.SweepEnabled = false; _state.Enabled = false; } @@ -60,18 +67,23 @@ void GbSquareChannel::ClockSweepUnit() uint16_t GbSquareChannel::GetSweepTargetFrequency() { uint16_t shiftResult = (_state.SweepFreq >> _state.SweepShift); - if(_state.SweepNegate) { + if (_state.SweepNegate) + { return _state.SweepFreq - shiftResult; - } else { + } + else + { return _state.SweepFreq + shiftResult; } } void GbSquareChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -80,15 +92,22 @@ void GbSquareChannel::ClockLengthCounter() void GbSquareChannel::ClockEnvelope() { - if(_state.EnvTimer > 0 && !_state.EnvStopped) { + if (_state.EnvTimer > 0 && !_state.EnvStopped) + { _state.EnvTimer--; - if(_state.EnvTimer == 0) { - if(_state.EnvRaiseVolume && _state.Volume < 0x0F) { + if (_state.EnvTimer == 0) + { + if (_state.EnvRaiseVolume && _state.Volume < 0x0F) + { _state.Volume++; - } else if(!_state.EnvRaiseVolume && _state.Volume > 0) { + } + else if (!_state.EnvRaiseVolume && _state.Volume > 0) + { _state.Volume--; - } else { + } + else + { _state.EnvStopped = true; } @@ -105,14 +124,18 @@ uint8_t GbSquareChannel::GetOutput() void GbSquareChannel::Exec(uint32_t clocksToRun) { _state.Timer -= clocksToRun; - if(_state.Enabled) { + if (_state.Enabled) + { _state.Output = _dutySequences[_state.Duty][_state.DutyPos] * _state.Volume; - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { _state.Timer = (2048 - _state.Frequency) * 4; _state.DutyPos = (_state.DutyPos + 1) & 0x07; } @@ -120,29 +143,32 @@ void GbSquareChannel::Exec(uint32_t clocksToRun) uint8_t GbSquareChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0x80, 0x3F, 0x00, 0xFF, 0xBF }; + constexpr uint8_t openBusBits[5] = {0x80, 0x3F, 0x00, 0xFF, 0xBF}; uint8_t value = 0; - switch(addr) { - case 0: - value = ( - (_state.SweepPeriod << 4) | - (_state.SweepNegate ? 0x08 : 0) | - _state.SweepShift - ); - break; + switch (addr) + { + case 0: + value = ( + (_state.SweepPeriod << 4) | + (_state.SweepNegate ? 0x08 : 0) | + _state.SweepShift + ); + break; - case 1: value = _state.Duty << 6; break; + case 1: value = _state.Duty << 6; + break; - case 2: - value = ( - (_state.EnvVolume << 4) | - (_state.EnvRaiseVolume ? 0x08 : 0) | - _state.EnvPeriod - ); - break; + case 2: + value = ( + (_state.EnvVolume << 4) | + (_state.EnvRaiseVolume ? 0x08 : 0) | + _state.EnvPeriod + ); + break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -150,30 +176,35 @@ uint8_t GbSquareChannel::Read(uint16_t addr) void GbSquareChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: - _state.SweepShift = value & 0x07; - _state.SweepNegate = (value & 0x08) != 0; - _state.SweepPeriod = (value & 0x70) >> 4; - break; + switch (addr) + { + case 0: + _state.SweepShift = value & 0x07; + _state.SweepNegate = (value & 0x08) != 0; + _state.SweepPeriod = (value & 0x70) >> 4; + break; - case 1: - _state.Length = 64 - (value & 0x3F); - _state.Duty = (value & 0xC0) >> 6; - break; + case 1: + _state.Length = 64 - (value & 0x3F); + _state.Duty = (value & 0xC0) >> 6; + break; - case 2: + case 2: { - if(_state.EnvPeriod == 0 && !_state.EnvStopped) { + if (_state.EnvPeriod == 0 && !_state.EnvStopped) + { //"If the old envelope period was zero and the envelope is still doing automatic updates, volume is incremented by 1" _state.Volume++; - } else if(!_state.EnvRaiseVolume) { + } + else if (!_state.EnvRaiseVolume) + { //"otherwise if the envelope was in subtract mode, volume is incremented by 2" _state.Volume += 2; } bool raiseVolume = (value & 0x08) != 0; - if(raiseVolume != _state.EnvRaiseVolume) { + if (raiseVolume != _state.EnvRaiseVolume) + { //"If the mode was changed (add to subtract or subtract to add), volume is set to 16 - volume." _state.Volume = 16 - _state.Volume; } @@ -185,20 +216,23 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.EnvRaiseVolume = raiseVolume; _state.EnvVolume = (value & 0xF0) >> 4; - if(!(value & 0xF8)) { + if (!(value & 0xF8)) + { _state.Enabled = false; } break; } - case 3: - _state.Frequency = (_state.Frequency & 0x700) | value; - break; + case 3: + _state.Frequency = (_state.Frequency & 0x700) | value; + break; - case 4: { + case 4: + { _state.Frequency = (_state.Frequency & 0xFF) | ((value & 0x07) << 8); - if(value & 0x80) { + if (value & 0x80) + { //"Writing a value to NRx4 with bit 7 set causes the following things to occur :" //"Channel is enabled, if volume is not 0 or raise volume flag is set" @@ -208,7 +242,8 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.Timer = (2048 - _state.Frequency) * 4; //"If length counter is zero, it is set to 64 (256 for wave channel)." - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 64; _state.LengthEnabled = false; } @@ -230,9 +265,11 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.SweepTimer = _state.SweepPeriod; _state.SweepEnabled = _state.SweepPeriod > 0 || _state.SweepShift > 0; - if(_state.SweepShift > 0) { + if (_state.SweepShift > 0) + { _state.SweepFreq = GetSweepTargetFrequency(); - if(_state.SweepFreq > 2047) { + if (_state.SweepFreq > 2047) + { _state.SweepEnabled = false; _state.Enabled = false; } @@ -248,8 +285,10 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) void GbSquareChannel::Serialize(Serializer& s) { s.Stream( - _state.SweepPeriod, _state.SweepNegate, _state.SweepShift, _state.SweepTimer, _state.SweepEnabled, _state.SweepFreq, - _state.Volume, _state.EnvVolume, _state.EnvRaiseVolume, _state.EnvPeriod, _state.EnvTimer, _state.Duty, _state.Frequency, + _state.SweepPeriod, _state.SweepNegate, _state.SweepShift, _state.SweepTimer, _state.SweepEnabled, + _state.SweepFreq, + _state.Volume, _state.EnvVolume, _state.EnvRaiseVolume, _state.EnvPeriod, _state.EnvTimer, _state.Duty, + _state.Frequency, _state.Length, _state.LengthEnabled, _state.Enabled, _state.Timer, _state.DutyPos, _state.Output ); } diff --git a/Core/GbSquareChannel.h b/Core/GbSquareChannel.h index d628592..424dfec 100644 --- a/Core/GbSquareChannel.h +++ b/Core/GbSquareChannel.h @@ -10,10 +10,10 @@ class GbSquareChannel final : public ISerializable { private: const uint8_t _dutySequences[4][8] = { - { 0, 1, 1, 1, 1, 1, 1, 1 }, - { 0, 0, 1, 1, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 0, 0, 1, 1 } + {0, 1, 1, 1, 1, 1, 1, 1}, + {0, 0, 1, 1, 1, 1, 1, 1}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 1, 1} }; GbSquareState _state = {}; @@ -27,7 +27,7 @@ public: bool Enabled(); void Disable(); - void ClockSweepUnit(); + void ClockSweepUnit(); uint16_t GetSweepTargetFrequency(); void ClockLengthCounter(); @@ -41,4 +41,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbTimer.cpp b/Core/GbTimer.cpp index 6cd4314..9cdbd02 100644 --- a/Core/GbTimer.cpp +++ b/Core/GbTimer.cpp @@ -8,7 +8,7 @@ void GbTimer::Init(GbMemoryManager* memoryManager, GbApu* apu) { _apu = apu; _memoryManager = memoryManager; - + _state = {}; _state.TimerDivider = 1024; @@ -28,9 +28,11 @@ GbTimerState GbTimer::GetState() void GbTimer::Exec() { - if((_state.Divider & 0x03) == 2) { + if ((_state.Divider & 0x03) == 2) + { _state.Reloaded = false; - if(_state.NeedReload) { + if (_state.NeedReload) + { ReloadCounter(); } } @@ -47,15 +49,18 @@ void GbTimer::ReloadCounter() void GbTimer::SetDivider(uint16_t newValue) { - if(_state.TimerEnabled && !(newValue & _state.TimerDivider) && (_state.Divider & _state.TimerDivider)) { + if (_state.TimerEnabled && !(newValue & _state.TimerDivider) && (_state.Divider & _state.TimerDivider)) + { _state.Counter++; - if(_state.Counter == 0) { + if (_state.Counter == 0) + { _state.NeedReload = true; } } uint16_t frameSeqBit = _memoryManager->IsHighSpeed() ? 0x2000 : 0x1000; - if(!(newValue & frameSeqBit) && (_state.Divider & frameSeqBit)) { + if (!(newValue & frameSeqBit) && (_state.Divider & frameSeqBit)) + { _apu->ClockFrameSequencer(); } @@ -64,68 +69,85 @@ void GbTimer::SetDivider(uint16_t newValue) uint8_t GbTimer::Read(uint16_t addr) { - switch(addr) { - case 0xFF04: return _state.Divider >> 8; - case 0xFF05: return _state.Counter; //FF05 - TIMA - Timer counter (R/W) - case 0xFF06: return _state.Modulo; //FF06 - TMA - Timer Modulo (R/W) - case 0xFF07: return _state.Control | 0xF8; //FF07 - TAC - Timer Control (R/W) + switch (addr) + { + case 0xFF04: return _state.Divider >> 8; + case 0xFF05: return _state.Counter; //FF05 - TIMA - Timer counter (R/W) + case 0xFF06: return _state.Modulo; //FF06 - TMA - Timer Modulo (R/W) + case 0xFF07: return _state.Control | 0xF8; //FF07 - TAC - Timer Control (R/W) } return 0; } void GbTimer::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF04: - SetDivider(0); - break; + switch (addr) + { + case 0xFF04: + SetDivider(0); + break; - case 0xFF05: - //FF05 - TIMA - Timer counter (R/W) - if(_state.NeedReload) { - //Writing to TIMA when a reload is pending will cancel the reload and IRQ request - _state.NeedReload = false; - } + case 0xFF05: + //FF05 - TIMA - Timer counter (R/W) + if (_state.NeedReload) + { + //Writing to TIMA when a reload is pending will cancel the reload and IRQ request + _state.NeedReload = false; + } - if(!_state.Reloaded) { - //Writes to TIMA on the cycle TIMA was reloaded with TMA are ignored - _state.Counter = value; - } - break; + if (!_state.Reloaded) + { + //Writes to TIMA on the cycle TIMA was reloaded with TMA are ignored + _state.Counter = value; + } + break; - case 0xFF06: - //FF06 - TMA - Timer Modulo (R/W) - _state.Modulo = value; - if(_state.Reloaded) { - //Writing to TMA on the same cycle it was reloaded into TIMA will also update TIMA - _state.Counter = value; - } - break; + case 0xFF06: + //FF06 - TMA - Timer Modulo (R/W) + _state.Modulo = value; + if (_state.Reloaded) + { + //Writing to TMA on the same cycle it was reloaded into TIMA will also update TIMA + _state.Counter = value; + } + break; - case 0xFF07: { + case 0xFF07: + { //FF07 - TAC - Timer Control (R/W) _state.Control = value; bool enabled = (value & 0x04) != 0; uint16_t newDivider = 0; - switch(value & 0x03) { - case 0: newDivider = 1 << 9; break; - case 1: newDivider = 1 << 3; break; - case 2: newDivider = 1 << 5; break; - case 3: newDivider = 1 << 7; break; + switch (value & 0x03) + { + case 0: newDivider = 1 << 9; + break; + case 1: newDivider = 1 << 3; + break; + case 2: newDivider = 1 << 5; + break; + case 3: newDivider = 1 << 7; + break; } - if(_state.TimerEnabled) { + if (_state.TimerEnabled) + { //When changing the value of TAC, the TIMA register can get incremented due to a glitch bool incrementCounter; - if(enabled) { + if (enabled) + { incrementCounter = (_state.Divider & _state.TimerDivider) != 0 && (_state.Divider & newDivider) == 0; - } else { + } + else + { incrementCounter = (_state.Divider & _state.TimerDivider) != 0; } - if(incrementCounter) { + if (incrementCounter) + { _state.Counter++; - if(_state.Counter == 0) { + if (_state.Counter == 0) + { ReloadCounter(); } } @@ -140,5 +162,6 @@ void GbTimer::Write(uint16_t addr, uint8_t value) void GbTimer::Serialize(Serializer& s) { - s.Stream(_state.Divider, _state.Counter, _state.Modulo, _state.Control, _state.TimerEnabled, _state.TimerDivider, _state.NeedReload, _state.Reloaded); + s.Stream(_state.Divider, _state.Counter, _state.Modulo, _state.Control, _state.TimerEnabled, _state.TimerDivider, + _state.NeedReload, _state.Reloaded); } diff --git a/Core/GbTimer.h b/Core/GbTimer.h index ff23e98..a5306ef 100644 --- a/Core/GbTimer.h +++ b/Core/GbTimer.h @@ -13,7 +13,7 @@ private: GbMemoryManager* _memoryManager = nullptr; GbApu* _apu = nullptr; GbTimerState _state = {}; - + void SetDivider(uint16_t value); void ReloadCounter(); @@ -30,4 +30,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbTypes.h b/Core/GbTypes.h index 959bc03..7ad253e 100644 --- a/Core/GbTypes.h +++ b/Core/GbTypes.h @@ -14,7 +14,7 @@ struct GbCpuState uint8_t C; uint8_t D; uint8_t E; - + uint8_t H; uint8_t L; @@ -50,7 +50,7 @@ class Register16 { uint8_t* _low; uint8_t* _high; - + public: Register16(uint8_t* high, uint8_t* low) { @@ -157,7 +157,7 @@ struct GbPpuState PpuMode Mode; PpuMode IrqMode; bool StatIrqFlag; - + uint8_t Ly; int16_t LyForCompare; @@ -186,11 +186,11 @@ struct GbPpuState bool CgbEnabled; uint8_t CgbVramBank; - + uint8_t CgbBgPalPosition; bool CgbBgPalAutoInc; uint16_t CgbBgPalettes[4 * 8]; - + uint8_t CgbObjPalPosition; bool CgbObjPalAutoInc; uint16_t CgbObjPalettes[4 * 8]; @@ -348,7 +348,7 @@ struct GbMemoryManagerState { uint64_t CycleCount; uint64_t ApuCycleCount; - + uint8_t CgbWorkRamBank; bool CgbSwitchSpeedRequest; bool CgbHighSpeed; @@ -385,7 +385,7 @@ struct GbState { GbType Type; GbCpuState Cpu; - GbPpuState Ppu; + GbPpuState Ppu; GbApuDebugState Apu; GbMemoryManagerState MemoryManager; GbTimerState Timer; diff --git a/Core/GbWaveChannel.cpp b/Core/GbWaveChannel.cpp index ab6bfac..dd44d13 100644 --- a/Core/GbWaveChannel.cpp +++ b/Core/GbWaveChannel.cpp @@ -29,9 +29,11 @@ void GbWaveChannel::Disable() void GbWaveChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -48,13 +50,17 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) _state.Timer -= clocksToRun; //The DAC receives the current value from the upper/lower nibble of the sample buffer, shifted right by the volume control. - if(_state.Volume && _state.Enabled) { + if (_state.Volume && _state.Enabled) + { _state.Output = _state.SampleBuffer >> (_state.Volume - 1); - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { //The wave channel's frequency timer period is set to (2048-frequency)*2. _state.Timer = (2048 - _state.Frequency) * 2; @@ -63,9 +69,12 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) _state.Position = (_state.Position + 1) & 0x1F; //then a sample is read into the sample buffer from this NEW position. - if(_state.Position & 0x01) { + if (_state.Position & 0x01) + { _state.SampleBuffer = _state.Ram[_state.Position >> 1] & 0x0F; - } else { + } + else + { _state.SampleBuffer = _state.Ram[_state.Position >> 1] >> 4; } } @@ -73,13 +82,17 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) uint8_t GbWaveChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0x7F, 0xFF, 0x9F, 0xFF, 0xBF }; + constexpr uint8_t openBusBits[5] = {0x7F, 0xFF, 0x9F, 0xFF, 0xBF}; uint8_t value = 0; - switch(addr) { - case 0: value = _state.DacEnabled ? 0x80 : 0; break; - case 2: value = _state.Volume << 5; break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + switch (addr) + { + case 0: value = _state.DacEnabled ? 0x80 : 0; + break; + case 2: value = _state.Volume << 5; + break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -87,28 +100,31 @@ uint8_t GbWaveChannel::Read(uint16_t addr) void GbWaveChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: - _state.DacEnabled = (value & 0x80) != 0; - _state.Enabled &= _state.DacEnabled; - break; + switch (addr) + { + case 0: + _state.DacEnabled = (value & 0x80) != 0; + _state.Enabled &= _state.DacEnabled; + break; - case 1: - _state.Length = 256 - value; - break; + case 1: + _state.Length = 256 - value; + break; - case 2: - _state.Volume = (value & 0x60) >> 5; - break; + case 2: + _state.Volume = (value & 0x60) >> 5; + break; - case 3: - _state.Frequency = (_state.Frequency & 0x700) | value; - break; + case 3: + _state.Frequency = (_state.Frequency & 0x700) | value; + break; - case 4: { + case 4: + { _state.Frequency = (_state.Frequency & 0xFF) | ((value & 0x07) << 8); - if(value & 0x80) { + if (value & 0x80) + { //Start playback //Channel is enabled, if DAC is enabled @@ -118,7 +134,8 @@ void GbWaveChannel::Write(uint16_t addr, uint8_t value) _state.Timer = (2048 - _state.Frequency) * 2; //If length counter is zero, it is set to 64 (256 for wave channel). - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 256; _state.LengthEnabled = false; } diff --git a/Core/GbWaveChannel.h b/Core/GbWaveChannel.h index 9f510f9..5901be0 100644 --- a/Core/GbWaveChannel.h +++ b/Core/GbWaveChannel.h @@ -31,4 +31,4 @@ public: uint8_t ReadRam(uint16_t addr); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/Gsu.Instructions.cpp b/Core/Gsu.Instructions.cpp index ccf933e..66a61d5 100644 --- a/Core/Gsu.Instructions.cpp +++ b/Core/Gsu.Instructions.cpp @@ -5,7 +5,8 @@ void Gsu::STOP() { - if(!_state.IrqDisabled) { + if (!_state.IrqDisabled) + { _state.SFR.Irq = true; _cpu->SetIrqSource(IrqSource::Coprocessor); } @@ -23,7 +24,8 @@ void Gsu::NOP() void Gsu::CACHE() { - if(_state.CacheBase != (_state.R[15] & 0xFFF0)) { + if (_state.CacheBase != (_state.R[15] & 0xFFF0)) + { _state.CacheBase = _state.R[15] & 0xFFF0; InvalidateCache(); } @@ -33,7 +35,8 @@ void Gsu::CACHE() void Gsu::Branch(bool branch) { int8_t offset = (int8_t)ReadOperand(); - if(branch) { + if (branch) + { WriteRegister(15, _state.R[15] + offset); } } @@ -95,14 +98,17 @@ void Gsu::BVS() void Gsu::JMP(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LJMP _state.ProgramBank = _state.R[reg] & 0x7F; WriteRegister(15, ReadSrcReg()); - + _state.CacheBase = _state.R[15] & 0xFFF0; InvalidateCache(); - } else { + } + else + { //JMP WriteRegister(15, _state.R[reg]); } @@ -111,11 +117,14 @@ void Gsu::JMP(uint8_t reg) void Gsu::TO(uint8_t reg) { - if(_state.SFR.Prefix) { + if (_state.SFR.Prefix) + { //MOVE WriteRegister(reg, ReadSrcReg()); ResetFlags(); - } else { + } + else + { //TO _state.DestReg = reg; } @@ -123,14 +132,17 @@ void Gsu::TO(uint8_t reg) void Gsu::FROM(uint8_t reg) { - if(_state.SFR.Prefix) { + if (_state.SFR.Prefix) + { //MOVES WriteDestReg(_state.R[reg]); _state.SFR.Overflow = (_state.R[reg] & 0x80) != 0; _state.SFR.Sign = (_state.R[reg] & 0x8000) != 0; _state.SFR.Zero = (_state.R[reg] == 0); ResetFlags(); - } else { + } + else + { //FROM _state.SrcReg = reg; } @@ -147,7 +159,8 @@ void Gsu::STORE(uint8_t reg) { _state.RamAddress = _state.R[reg]; WriteRam(_state.RamAddress, (uint8_t)ReadSrcReg()); - if(!_state.SFR.Alt1) { + if (!_state.SFR.Alt1) + { WriteRam(_state.RamAddress ^ 0x01, ReadSrcReg() >> 8); } ResetFlags(); @@ -157,7 +170,8 @@ void Gsu::LOAD(uint8_t reg) { _state.RamAddress = _state.R[reg]; uint16_t value = ReadRamBuffer(_state.RamAddress); - if(!_state.SFR.Alt1) { + if (!_state.SFR.Alt1) + { value |= ReadRamBuffer(_state.RamAddress ^ 0x01) << 8; } WriteDestReg(value); @@ -169,9 +183,10 @@ void Gsu::LOOP() _state.R[12]--; _state.SFR.Zero = (_state.R[12] == 0); _state.SFR.Sign = (_state.R[12] & 0x8000) != 0; - + //Loop until counter hits zero - if(!_state.SFR.Zero) { + if (!_state.SFR.Zero) + { WriteRegister(15, _state.R[13]); } @@ -220,15 +235,19 @@ void Gsu::SWAP() void Gsu::Add(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint32_t result = ReadSrcReg() + operand; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //ADC - Add with carry result += (uint8_t)_state.SFR.Carry; } @@ -245,15 +264,19 @@ void Gsu::Add(uint8_t reg) void Gsu::SubCompare(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2 && !_state.SFR.Alt1) { + if (_state.SFR.Alt2 && !_state.SFR.Alt1) + { //Immediate value, SUB #val operand = reg; - } else { + } + else + { operand = _state.R[reg]; } int32_t result = ReadSrcReg() - operand; - if(!_state.SFR.Alt2 && _state.SFR.Alt1) { + if (!_state.SFR.Alt2 && _state.SFR.Alt1) + { //SBC - SUB with carry result -= _state.SFR.Carry ? 0 : 1; } @@ -263,7 +286,8 @@ void Gsu::SubCompare(uint8_t reg) _state.SFR.Sign = (result & 0x8000) != 0; _state.SFR.Zero = (result & 0xFFFF) == 0; - if(!_state.SFR.Alt2 || !_state.SFR.Alt1) { + if (!_state.SFR.Alt2 || !_state.SFR.Alt1) + { //SUB/SBC, other CMP (and no write occurs for CMP) WriteDestReg(result); } @@ -273,22 +297,28 @@ void Gsu::SubCompare(uint8_t reg) void Gsu::MULT(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //UMULT - Unsigned multiply value = (uint16_t)((uint8_t)ReadSrcReg() * (uint8_t)operand); - } else { + } + else + { //MULT - Signed multiply value = (uint16_t)((int8_t)ReadSrcReg() * (int8_t)operand); } - + WriteDestReg(value); _state.SFR.Sign = (value & 0x8000) != 0; _state.SFR.Zero = value == 0; @@ -302,7 +332,8 @@ void Gsu::FMultLMult() { uint32_t multResult = (int16_t)ReadSrcReg() * (int16_t)_state.R[6]; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LMULT - "16x16 signed multiply", LSB in R4, MSB in DREG _state.R[4] = multResult; } @@ -321,18 +352,24 @@ void Gsu::FMultLMult() void Gsu::AndBitClear(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //Bit clear value = ReadSrcReg() & ~operand; - } else { + } + else + { //AND value = ReadSrcReg() & operand; } @@ -380,7 +417,7 @@ void Gsu::LSR() { uint16_t src = ReadSrcReg(); _state.SFR.Carry = (src & 0x01) != 0; - + uint16_t dst = src >> 1; WriteDestReg(dst); _state.SFR.Zero = dst == 0; @@ -407,7 +444,8 @@ void Gsu::ASR() _state.SFR.Carry = (src & 0x01) != 0; uint16_t dst = (int16_t)src >> 1; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { dst += (src + 1) >> 16; } @@ -420,7 +458,7 @@ void Gsu::ASR() void Gsu::ROR() { uint16_t src = ReadSrcReg(); - + uint16_t dst = (src >> 1) | ((int)_state.SFR.Carry << 15); _state.SFR.Carry = (src & 0x01) != 0; @@ -452,19 +490,24 @@ void Gsu::HIB() void Gsu::IbtSmsLms(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LMS - "Load word data from RAM, short address" _state.RamAddress = ReadOperand() << 1; uint8_t lsb = ReadRamBuffer(_state.RamAddress); uint8_t msb = ReadRamBuffer(_state.RamAddress | 0x01); WriteRegister(reg, (msb << 8) | lsb); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //SMS - "Store word data to RAM, short address" _state.RamAddress = ReadOperand() << 1; WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); WriteRam(_state.RamAddress | 0x01, _state.R[reg] >> 8); - } else { + } + else + { //IBT - "Load immediate byte data" WriteRegister(reg, (int8_t)ReadOperand()); } @@ -473,7 +516,8 @@ void Gsu::IbtSmsLms(uint8_t reg) void Gsu::IwtLmSm(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LM - Load memory _state.RamAddress = ReadOperand(); _state.RamAddress |= ReadOperand() << 8; @@ -481,14 +525,18 @@ void Gsu::IwtLmSm(uint8_t reg) uint8_t lsb = ReadRamBuffer(_state.RamAddress); uint8_t msb = ReadRamBuffer(_state.RamAddress ^ 0x01); WriteRegister(reg, (msb << 8) | lsb); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //SM - Store Memory _state.RamAddress = ReadOperand(); _state.RamAddress |= ReadOperand() << 8; WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); WriteRam(_state.RamAddress ^ 0x01, _state.R[reg] >> 8); - } else { + } + else + { //IWT - Load immediate word uint8_t lsb = ReadOperand(); uint8_t msb = ReadOperand(); @@ -500,19 +548,25 @@ void Gsu::IwtLmSm(uint8_t reg) void Gsu::OrXor(uint8_t operand) { uint16_t operandValue; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operandValue = operand; - } else { + } + else + { //Indirect register value operandValue = _state.R[operand]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //XOR value = ReadSrcReg() ^ operandValue; - } else { + } + else + { //OR value = ReadSrcReg() | operandValue; } @@ -540,14 +594,19 @@ void Gsu::DEC(uint8_t reg) void Gsu::GetCRamBRomB() { - if(!_state.SFR.Alt2) { + if (!_state.SFR.Alt2) + { //GETC - "Get byte from ROM to color register" _state.ColorReg = GetColor(ReadRomBuffer()); - } else if(!_state.SFR.Alt1) { + } + else if (!_state.SFR.Alt1) + { //RAMB - "Set RAM data bank" WaitRamOperation(); _state.RamBank = ReadSrcReg() & 0x01; - } else { + } + else + { //ROMB - "Set ROM data bank" WaitRomOperation(); _state.RomBank = ReadSrcReg() & 0x7F; @@ -557,16 +616,23 @@ void Gsu::GetCRamBRomB() void Gsu::GETB() { - if(_state.SFR.Alt2 && _state.SFR.Alt1) { + if (_state.SFR.Alt2 && _state.SFR.Alt1) + { //GETBS - "Get signed byte from ROM buffer" WriteDestReg((int8_t)ReadRomBuffer()); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //GETBL - "Get low byte from ROM buffer" WriteDestReg((ReadSrcReg() & 0xFF00) | ReadRomBuffer()); - } else if(_state.SFR.Alt1) { + } + else if (_state.SFR.Alt1) + { //GETBH - "Get high byte from ROM buffer" WriteDestReg((ReadSrcReg() & 0xFF) | (ReadRomBuffer() << 8)); - } else { + } + else + { //GETB - "Get byte from ROM buffer" WriteDestReg(ReadRomBuffer()); } @@ -575,13 +641,16 @@ void Gsu::GETB() void Gsu::PlotRpix() { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //RPIX - "Read pixel color" uint8_t value = ReadPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); _state.SFR.Zero = (value == 0); _state.SFR.Sign = (value & 0x8000); WriteDestReg(value); - } else { + } + else + { //PLOT DrawPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); _state.R[1]++; @@ -591,7 +660,8 @@ void Gsu::PlotRpix() void Gsu::ColorCMode() { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //CMODE - "Set plot mode" uint8_t value = (uint8_t)ReadSrcReg(); _state.PlotTransparent = (value & 0x01) != 0; @@ -599,7 +669,9 @@ void Gsu::ColorCMode() _state.ColorHighNibble = (value & 0x04) != 0; _state.ColorFreezeHigh = (value & 0x08) != 0; _state.ObjMode = (value & 0x10) != 0; - } else { + } + else + { //COLOR - "Set plot color" _state.ColorReg = GetColor((uint8_t)ReadSrcReg()); } @@ -608,12 +680,17 @@ void Gsu::ColorCMode() uint16_t Gsu::GetTileIndex(uint8_t x, uint8_t y) { - switch(_state.ObjMode ? 3 : _state.ScreenHeight) { - default: - case 0: return ((x & 0xF8) << 1) + ((y & 0xF8) >> 3); break; - case 1: return ((x & 0xF8) << 1) + ((x & 0xF8) >> 1) + ((y & 0xF8) >> 3); break; - case 2: return ((x & 0xF8) << 1) + ((x & 0xF8) << 0) + ((y & 0xF8) >> 3); break; - case 3: return ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; + switch (_state.ObjMode ? 3 : _state.ScreenHeight) + { + default: + case 0: return ((x & 0xF8) << 1) + ((y & 0xF8) >> 3); + break; + case 1: return ((x & 0xF8) << 1) + ((x & 0xF8) >> 1) + ((y & 0xF8) >> 3); + break; + case 2: return ((x & 0xF8) << 1) + ((x & 0xF8) << 0) + ((y & 0xF8) >> 3); + break; + case 3: return ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); + break; } } @@ -629,11 +706,12 @@ uint8_t Gsu::ReadPixel(uint8_t x, uint8_t y) WritePixelCache(_state.PrimaryCache); uint32_t tileAddress = GetTileAddress(x, y); - + x = (x & 7) ^ 7; uint8_t data = 0; - for(int i = 0; i < _state.PlotBpp; i++) { + for (int i = 0; i < _state.PlotBpp; i++) + { //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) uint8_t byteOffset = ((i >> 1) << 4) + (i & 0x01); data |= ((ReadGsu(tileAddress + byteOffset, MemoryOperationType::Read) >> x) & 1) << i; @@ -647,36 +725,42 @@ bool Gsu::IsTransparentPixel() { uint8_t color = _state.ColorFreezeHigh ? (_state.ColorReg & 0x0F) : _state.ColorReg; - switch(_state.PlotBpp) { - default: - case 2: return (color & 0x03) == 0; - case 4: return (color & 0x0F) == 0; - case 8: return color == 0; + switch (_state.PlotBpp) + { + default: + case 2: return (color & 0x03) == 0; + case 4: return (color & 0x0F) == 0; + case 8: return color == 0; } } void Gsu::DrawPixel(uint8_t x, uint8_t y) { - if(!_state.PlotTransparent && IsTransparentPixel()) { + if (!_state.PlotTransparent && IsTransparentPixel()) + { return; } uint8_t color = _state.ColorReg; - if(_state.PlotDither && _state.PlotBpp != 8) { - if((x ^ y) & 0x01) { + if (_state.PlotDither && _state.PlotBpp != 8) + { + if ((x ^ y) & 0x01) + { color >>= 4; } color &= 0x0F; } - if(_state.PrimaryCache.X != (x & 0xF8) || _state.PrimaryCache.Y != y) { + if (_state.PrimaryCache.X != (x & 0xF8) || _state.PrimaryCache.Y != y) + { FlushPrimaryCache(x, y); } uint8_t xOffset = (x & 7) ^ 7; _state.PrimaryCache.Pixels[xOffset] = color; _state.PrimaryCache.ValidBits |= (1 << xOffset); - if(_state.PrimaryCache.ValidBits == 0xFF) { + if (_state.PrimaryCache.ValidBits == 0xFF) + { FlushPrimaryCache(x, y); } } @@ -690,24 +774,28 @@ void Gsu::FlushPrimaryCache(uint8_t x, uint8_t y) _state.PrimaryCache.Y = y; } -void Gsu::WritePixelCache(GsuPixelCache &cache) +void Gsu::WritePixelCache(GsuPixelCache& cache) { - if(cache.ValidBits == 0) { + if (cache.ValidBits == 0) + { return; } uint32_t tileAddress = GetTileAddress(cache.X, cache.Y); - for(int i = 0; i < _state.PlotBpp; i++) { + for (int i = 0; i < _state.PlotBpp; i++) + { uint8_t value = 0; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { value |= ((cache.Pixels[x] >> i) & 0x01) << x; } //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) uint8_t byte = ((i >> 1) << 4) + (i & 0x01); - if(cache.ValidBits != 0xFF) { + if (cache.ValidBits != 0xFF) + { //Read the pixels in memory before to merge them before writing the cache's content to memory Step(_state.ClockSelect ? 5 : 6); value &= cache.ValidBits; @@ -724,12 +812,14 @@ void Gsu::WritePixelCache(GsuPixelCache &cache) uint8_t Gsu::GetColor(uint8_t value) { - if(_state.ColorHighNibble) { + if (_state.ColorHighNibble) + { return (_state.ColorReg & 0xF0) | (value >> 4); } - if(_state.ColorFreezeHigh) { + if (_state.ColorFreezeHigh) + { return (_state.ColorReg & 0xF0) | (value & 0x0F); } return value; -} \ No newline at end of file +} diff --git a/Core/Gsu.cpp b/Core/Gsu.cpp index e3aca33..bd94398 100644 --- a/Core/Gsu.cpp +++ b/Core/Gsu.cpp @@ -12,7 +12,7 @@ #include "BatteryManager.h" #include "../Utilities/HexUtilities.h" -Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType::Register) +Gsu::Gsu(Console* console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType::Register) { _console = console; _memoryManager = console->GetMemoryManager().get(); @@ -31,15 +31,18 @@ Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType _gsuRam = new uint8_t[_gsuRamSize]; _settings->InitializeRam(_gsuRam, _gsuRamSize); - for(uint32_t i = 0; i < _gsuRamSize / 0x1000; i++) { - _gsuRamHandlers.push_back(unique_ptr(new RamHandler(_gsuRam, i * 0x1000, _gsuRamSize, SnesMemoryType::GsuWorkRam))); + for (uint32_t i = 0; i < _gsuRamSize / 0x1000; i++) + { + _gsuRamHandlers.push_back( + unique_ptr(new RamHandler(_gsuRam, i * 0x1000, _gsuRamSize, SnesMemoryType::GsuWorkRam))); _gsuCpuRamHandlers.push_back(unique_ptr(new GsuRamHandler(_state, _gsuRamHandlers.back().get()))); } - + //CPU mappings - MemoryMappings *cpuMappings = _memoryManager->GetMemoryMappings(); - vector> &prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers(); - for(unique_ptr &handler : prgRomHandlers) { + MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); + vector>& prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers(); + for (unique_ptr& handler : prgRomHandlers) + { _gsuCpuRomHandlers.push_back(unique_ptr(new GsuRomHandler(_state, handler.get()))); } @@ -47,7 +50,8 @@ Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType cpuMappings->RegisterHandler(0x00, 0x3F, 0x3000, 0x3FFF, this); cpuMappings->RegisterHandler(0x80, 0xBF, 0x3000, 0x3FFF, this); - for(int i = 0; i < 0x3F; i++) { + for (int i = 0; i < 0x3F; i++) + { cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, _gsuCpuRamHandlers); cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _gsuCpuRamHandlers); } @@ -76,7 +80,8 @@ Gsu::~Gsu() void Gsu::ProcessEndOfFrame() { uint8_t clockMultiplier = _settings->GetEmulationConfig().GsuClockSpeed / 100; - if(_clockMultiplier != clockMultiplier) { + if (_clockMultiplier != clockMultiplier) + { _state.CycleCount = _state.CycleCount / _clockMultiplier * clockMultiplier; _clockMultiplier = clockMultiplier; } @@ -86,11 +91,13 @@ void Gsu::Run() { uint64_t targetCycle = _memoryManager->GetMasterClock() * _clockMultiplier; - while(!_stopped && _state.CycleCount < targetCycle) { + while (!_stopped && _state.CycleCount < targetCycle) + { Exec(); } - if(targetCycle > _state.CycleCount) { + if (targetCycle > _state.CycleCount) + { Step(targetCycle - _state.CycleCount); } } @@ -99,148 +106,382 @@ void Gsu::Exec() { uint8_t opCode = ReadOpCode(); - switch(opCode) { - case 0x00: STOP(); break; - case 0x01: NOP(); break; - case 0x02: CACHE(); break; - case 0x03: LSR(); break; - case 0x04: ROL(); break; - case 0x05: BRA(); break; - case 0x06: BLT(); break; - case 0x07: BGE(); break; - case 0x08: BNE(); break; - case 0x09: BEQ(); break; - case 0x0A: BPL(); break; - case 0x0B: BMI(); break; - case 0x0C: BCC(); break; - case 0x0D: BCS(); break; - case 0x0E: BCV(); break; - case 0x0F: BVS(); break; + switch (opCode) + { + case 0x00: STOP(); + break; + case 0x01: NOP(); + break; + case 0x02: CACHE(); + break; + case 0x03: LSR(); + break; + case 0x04: ROL(); + break; + case 0x05: BRA(); + break; + case 0x06: BLT(); + break; + case 0x07: BGE(); + break; + case 0x08: BNE(); + break; + case 0x09: BEQ(); + break; + case 0x0A: BPL(); + break; + case 0x0B: BMI(); + break; + case 0x0C: BCC(); + break; + case 0x0D: BCS(); + break; + case 0x0E: BCV(); + break; + case 0x0F: BVS(); + break; - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: - TO(opCode & 0x0F); - break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + TO(opCode & 0x0F); + break; - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: - WITH(opCode & 0x0F); - break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + WITH(opCode & 0x0F); + break; - case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3A: case 0x3B: - STORE(opCode & 0x0F); - break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + STORE(opCode & 0x0F); + break; - case 0x3C: LOOP(); break; - case 0x3D: ALT1(); break; - case 0x3E: ALT2(); break; - case 0x3F: ALT3(); break; + case 0x3C: LOOP(); + break; + case 0x3D: ALT1(); + break; + case 0x3E: ALT2(); + break; + case 0x3F: ALT3(); + break; - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4A: case 0x4B: - LOAD(opCode & 0x0F); - break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + LOAD(opCode & 0x0F); + break; - case 0x4C: PlotRpix(); break; - case 0x4D: SWAP(); break; - case 0x4E: ColorCMode(); break; - case 0x4F: NOT(); break; + case 0x4C: PlotRpix(); + break; + case 0x4D: SWAP(); + break; + case 0x4E: ColorCMode(); + break; + case 0x4F: NOT(); + break; - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: - Add(opCode & 0x0F); - break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + Add(opCode & 0x0F); + break; - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: - SubCompare(opCode & 0x0F); - break; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + SubCompare(opCode & 0x0F); + break; - case 0x70: MERGE(); break; + case 0x70: MERGE(); + break; - case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - AndBitClear(opCode & 0x0F); - break; + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + AndBitClear(opCode & 0x0F); + break; - case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: - MULT(opCode & 0x0F); - break; + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + MULT(opCode & 0x0F); + break; - case 0x90: SBK(); break; + case 0x90: SBK(); + break; - case 0x91: LINK(1); break; - case 0x92: LINK(2); break; - case 0x93: LINK(3); break; - case 0x94: LINK(4); break; + case 0x91: LINK(1); + break; + case 0x92: LINK(2); + break; + case 0x93: LINK(3); + break; + case 0x94: LINK(4); + break; - case 0x95: SignExtend(); break; + case 0x95: SignExtend(); + break; - case 0x96: ASR(); break; - case 0x97: ROR(); break; + case 0x96: ASR(); + break; + case 0x97: ROR(); + break; - case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: - JMP(opCode & 0x0F); - break; + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + JMP(opCode & 0x0F); + break; - case 0x9E: LOB(); break; - case 0x9F: FMultLMult(); break; + case 0x9E: LOB(); + break; + case 0x9F: FMultLMult(); + break; - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - IbtSmsLms(opCode & 0x0F); - break; + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + IbtSmsLms(opCode & 0x0F); + break; - case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: - case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: - FROM(opCode & 0x0F); - break; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + FROM(opCode & 0x0F); + break; - case 0xC0: HIB(); break; + case 0xC0: HIB(); + break; - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: - case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: - OrXor(opCode & 0x0F); - break; + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + OrXor(opCode & 0x0F); + break; - case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: - case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: - INC(opCode & 0x0F); - break; + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + INC(opCode & 0x0F); + break; - case 0xDF: GetCRamBRomB(); break; + case 0xDF: GetCRamBRomB(); + break; - case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: - case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: - DEC(opCode & 0x0F); - break; + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + DEC(opCode & 0x0F); + break; - case 0xEF: GETB(); break; + case 0xEF: GETB(); + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - IwtLmSm(opCode & 0x0F); - break; + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + IwtLmSm(opCode & 0x0F); + break; } _console->ProcessMemoryRead(_lastOpAddr, _state.ProgramReadBuffer, MemoryOperationType::ExecOpCode); - if(!_r15Changed) { + if (!_r15Changed) + { _state.R[15]++; - } else { + } + else + { _r15Changed = false; } } uint8_t Gsu::ReadGsu(uint32_t addr, MemoryOperationType opType) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); uint8_t value; - if(handler) { + if (handler) + { value = handler->Read(addr); - } else { + } + else + { //TODO: Open bus? value = 0; LogDebug("[Debug] GSU - Missing read handler: " + HexUtilities::ToHex(addr)); @@ -252,10 +493,13 @@ uint8_t Gsu::ReadGsu(uint32_t addr, MemoryOperationType opType) void Gsu::WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType) { - IMemoryHandler *handler = _mappings.GetHandler(addr); - if(handler) { + IMemoryHandler* handler = _mappings.GetHandler(addr); + if (handler) + { handler->Write(addr, value); - } else { + } + else + { LogDebug("[Debug] GSU - Missing write handler: " + HexUtilities::ToHex(addr)); } _console->ProcessMemoryWrite(addr, value, opType); @@ -264,20 +508,24 @@ void Gsu::WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType) void Gsu::InitProgramCache(uint16_t cacheAddr) { uint16_t dest = (cacheAddr & 0x01F0); - - if(_state.ProgramBank <= 0x5F) { + + if (_state.ProgramBank <= 0x5F) + { WaitRomOperation(); WaitForRomAccess(); - } else { + } + else + { WaitRamOperation(); WaitForRamAccess(); } - + uint32_t srcBaseAddr = (_state.ProgramBank << 16) + _state.CacheBase + dest; - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { _cache[dest + i] = ReadGsu(srcBaseAddr + i, MemoryOperationType::Read); } - Step(_state.ClockSelect ? 5*16 : 6*16); + Step(_state.ClockSelect ? 5 * 16 : 6 * 16); _cacheValid[cacheAddr >> 4] = true; } @@ -301,19 +549,26 @@ uint8_t Gsu::ReadProgramByte(MemoryOperationType opType) { _lastOpAddr = (_state.ProgramBank << 16) | _state.R[15]; uint16_t cacheAddr = _state.R[15] - _state.CacheBase; - if(cacheAddr < 512) { - if(!_cacheValid[cacheAddr >> 4]) { + if (cacheAddr < 512) + { + if (!_cacheValid[cacheAddr >> 4]) + { InitProgramCache(cacheAddr & 0xFFF0); } - + Step(_state.ClockSelect ? 1 : 2); _console->ProcessMemoryRead(_lastOpAddr, _cache[cacheAddr], opType); return _cache[cacheAddr]; - } else { - if(_state.ProgramBank <= 0x5F) { + } + else + { + if (_state.ProgramBank <= 0x5F) + { WaitRomOperation(); WaitForRomAccess(); - } else { + } + else + { WaitRamOperation(); WaitForRamAccess(); } @@ -335,11 +590,14 @@ void Gsu::WriteDestReg(uint16_t value) void Gsu::WriteRegister(uint8_t reg, uint16_t value) { _state.R[reg] = value; - - if(reg == 14) { + + if (reg == 14) + { _state.SFR.RomReadPending = true; _state.RomDelay = _state.ClockSelect ? 5 : 6; - } else if(reg == 15) { + } + else if (reg == 15) + { _r15Changed = true; } } @@ -361,7 +619,8 @@ void Gsu::InvalidateCache() void Gsu::WaitRomOperation() { - if(_state.RomDelay) { + if (_state.RomDelay) + { //Wait for existing RAM operation to complete Step(_state.RomDelay); } @@ -369,7 +628,8 @@ void Gsu::WaitRomOperation() void Gsu::WaitRamOperation() { - if(_state.RamDelay) { + if (_state.RamDelay) + { //Wait for existing RAM operation to complete Step(_state.RamDelay); } @@ -377,7 +637,8 @@ void Gsu::WaitRamOperation() void Gsu::WaitForRomAccess() { - if(!_state.GsuRomAccess) { + if (!_state.GsuRomAccess) + { _waitForRomAccess = true; _stopped = true; } @@ -385,7 +646,8 @@ void Gsu::WaitForRomAccess() void Gsu::WaitForRamAccess() { - if(!_state.GsuRamAccess) { + if (!_state.GsuRamAccess) + { _waitForRamAccess = true; _stopped = true; } @@ -422,20 +684,25 @@ void Gsu::Step(uint64_t cycles) { _state.CycleCount += cycles; - if(_state.RomDelay) { + if (_state.RomDelay) + { _state.RomDelay -= std::min((uint8_t)cycles, _state.RomDelay); - if(_state.RomDelay == 0) { + if (_state.RomDelay == 0) + { WaitForRomAccess(); _state.RomReadBuffer = ReadGsu((_state.RomBank << 16) | _state.R[14], MemoryOperationType::Read); _state.SFR.RomReadPending = false; } } - if(_state.RamDelay) { + if (_state.RamDelay) + { _state.RamDelay -= std::min((uint8_t)cycles, _state.RamDelay); - if(_state.RamDelay == 0) { + if (_state.RamDelay == 0) + { WaitForRamAccess(); - WriteGsu(0x700000 | (_state.RamBank << 16) | _state.RamWriteAddress, _state.RamWriteValue, MemoryOperationType::Write); + WriteGsu(0x700000 | (_state.RamBank << 16) | _state.RamWriteAddress, _state.RamWriteValue, + MemoryOperationType::Write); } } } @@ -444,7 +711,7 @@ void Gsu::Reset() { _state = {}; _state.ProgramReadBuffer = 0x01; //Run a NOP on first cycle - + _console->GetSettings()->InitializeRam(_cache, 512); memset(_cacheValid, 0, sizeof(_cacheValid)); _waitForRomAccess = false; @@ -456,37 +723,69 @@ void Gsu::Reset() uint8_t Gsu::Read(uint32_t addr) { addr &= 0x33FF; - if(_state.SFR.Running && addr != 0x3030 && addr != 0x3031 && addr != 0x303B) { + if (_state.SFR.Running && addr != 0x3030 && addr != 0x3031 && addr != 0x303B) + { //"During GSU operation, only SFR, SCMR, and VCR may be accessed." return 0; } - switch(addr) { - case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C:case 0x300E: - case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C:case 0x301E: - return (uint8_t)_state.R[(addr >> 1) & 0x0F]; + switch (addr) + { + case 0x3000: + case 0x3002: + case 0x3004: + case 0x3006: + case 0x3008: + case 0x300A: + case 0x300C: + case 0x300E: + case 0x3010: + case 0x3012: + case 0x3014: + case 0x3016: + case 0x3018: + case 0x301A: + case 0x301C: + case 0x301E: + return (uint8_t)_state.R[(addr >> 1) & 0x0F]; - case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D:case 0x300F: - case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D:case 0x301F: - return _state.R[(addr >> 1) & 0x0F] >> 8; + case 0x3001: + case 0x3003: + case 0x3005: + case 0x3007: + case 0x3009: + case 0x300B: + case 0x300D: + case 0x300F: + case 0x3011: + case 0x3013: + case 0x3015: + case 0x3017: + case 0x3019: + case 0x301B: + case 0x301D: + case 0x301F: + return _state.R[(addr >> 1) & 0x0F] >> 8; - case 0x3030: return _state.SFR.GetFlagsLow(); - case 0x3031: { + case 0x3030: return _state.SFR.GetFlagsLow(); + case 0x3031: + { uint8_t flags = _state.SFR.GetFlagsHigh(); _state.SFR.Irq = false; _cpu->ClearIrqSource(IrqSource::Coprocessor); return flags; } - case 0x3034: return _state.ProgramBank; - case 0x3036: return _state.RomBank; - case 0x303B: return 0x04; //Version (can be 1 or 4?) - case 0x303C: return _state.RamBank; - case 0x303E: return (uint8_t)_state.CacheBase; - case 0x303F: return _state.CacheBase >> 8; + case 0x3034: return _state.ProgramBank; + case 0x3036: return _state.RomBank; + case 0x303B: return 0x04; //Version (can be 1 or 4?) + case 0x303C: return _state.RamBank; + case 0x303E: return (uint8_t)_state.CacheBase; + case 0x303F: return _state.CacheBase >> 8; } - - if(addr >= 0x3100 && addr <= 0x32FF) { + + if (addr >= 0x3100 && addr <= 0x32FF) + { return _cache[(_state.CacheBase + (addr - 0x3100)) & 0x1FF]; } @@ -499,33 +798,68 @@ uint8_t Gsu::Read(uint32_t addr) void Gsu::Write(uint32_t addr, uint8_t value) { addr &= 0x33FF; - if(_state.SFR.Running && addr != 0x3030 && addr != 0x303A) { + if (_state.SFR.Running && addr != 0x3030 && addr != 0x303A) + { //"During GSU operation, only SFR, SCMR, and VCR may be accessed." return; } - switch(addr) { - case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C: case 0x300E: - case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C: case 0x301E: - _state.RegisterLatch = value; - break; + switch (addr) + { + case 0x3000: + case 0x3002: + case 0x3004: + case 0x3006: + case 0x3008: + case 0x300A: + case 0x300C: + case 0x300E: + case 0x3010: + case 0x3012: + case 0x3014: + case 0x3016: + case 0x3018: + case 0x301A: + case 0x301C: + case 0x301E: + _state.RegisterLatch = value; + break; - case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D: case 0x300F: - case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D: case 0x301F: { + case 0x3001: + case 0x3003: + case 0x3005: + case 0x3007: + case 0x3009: + case 0x300B: + case 0x300D: + case 0x300F: + case 0x3011: + case 0x3013: + case 0x3015: + case 0x3017: + case 0x3019: + case 0x301B: + case 0x301D: + case 0x301F: + { uint8_t reg = (addr >> 1) & 0x0F; _state.R[reg] = (value << 8) | _state.RegisterLatch; - - if(reg == 14) { + + if (reg == 14) + { _state.SFR.RomReadPending = true; _state.RomDelay = _state.ClockSelect ? 5 : 6; - } else if(addr == 0x301F) { + } + else if (addr == 0x301F) + { _state.SFR.Running = true; UpdateRunningState(); } break; } - case 0x3030: { + case 0x3030: + { bool running = _state.SFR.Running; _state.SFR.Zero = (value & 0x02) != 0; _state.SFR.Carry = (value & 0x04) != 0; @@ -533,7 +867,8 @@ void Gsu::Write(uint32_t addr, uint8_t value) _state.SFR.Overflow = (value & 0x10) != 0; _state.SFR.Running = (value & 0x20) != 0; - if(running && !_state.SFR.Running) { + if (running && !_state.SFR.Running) + { _state.CacheBase = 0; InvalidateCache(); } @@ -541,43 +876,57 @@ void Gsu::Write(uint32_t addr, uint8_t value) break; } - case 0x3033: _state.BackupRamEnabled = (value & 0x01); break; - case 0x3034: _state.ProgramBank = (value & 0x7F); InvalidateCache(); break; - - case 0x3037: - _state.HighSpeedMode = (value & 0x20) != 0; - _state.IrqDisabled = (value & 0x80) != 0; + case 0x3033: _state.BackupRamEnabled = (value & 0x01); + break; + case 0x3034: _state.ProgramBank = (value & 0x7F); + InvalidateCache(); + break; + + case 0x3037: + _state.HighSpeedMode = (value & 0x20) != 0; + _state.IrqDisabled = (value & 0x80) != 0; + break; + + case 0x3038: _state.ScreenBase = value; + break; + case 0x3039: _state.ClockSelect = (value & 0x01); + break; + + case 0x303A: + _state.ColorGradient = (value & 0x03); + switch (_state.ColorGradient) + { + case 0: _state.PlotBpp = 2; break; - - case 0x3038: _state.ScreenBase = value; break; - case 0x3039: _state.ClockSelect = (value & 0x01); break; - - case 0x303A: - _state.ColorGradient = (value & 0x03); - switch(_state.ColorGradient) { - case 0: _state.PlotBpp = 2; break; - case 1: _state.PlotBpp = 4; break; - case 2: _state.PlotBpp = 4; break; - case 3: _state.PlotBpp = 8; break; - } - _state.ScreenHeight = ((value & 0x04) >> 2) | ((value & 0x20) >> 4); - _state.GsuRamAccess = (value & 0x08) != 0; - _state.GsuRomAccess = (value & 0x10) != 0; - - if(_state.GsuRamAccess) { - _waitForRamAccess = false; - } - if(_state.GsuRomAccess) { - _waitForRomAccess = false; - } - UpdateRunningState(); + case 1: _state.PlotBpp = 4; break; + case 2: _state.PlotBpp = 4; + break; + case 3: _state.PlotBpp = 8; + break; + } + _state.ScreenHeight = ((value & 0x04) >> 2) | ((value & 0x20) >> 4); + _state.GsuRamAccess = (value & 0x08) != 0; + _state.GsuRomAccess = (value & 0x10) != 0; + + if (_state.GsuRamAccess) + { + _waitForRamAccess = false; + } + if (_state.GsuRomAccess) + { + _waitForRomAccess = false; + } + UpdateRunningState(); + break; } - if(addr >= 0x3100 && addr <= 0x32FF) { + if (addr >= 0x3100 && addr <= 0x32FF) + { uint16_t cacheAddr = (_state.CacheBase + (addr - 0x3100)) & 0x1FF; _cache[cacheAddr] = value; - if((cacheAddr & 0x0F) == 0x0F) { + if ((cacheAddr & 0x0F) == 0x0F) + { _cacheValid[cacheAddr >> 4] = true; } } @@ -588,27 +937,32 @@ uint8_t Gsu::Peek(uint32_t addr) return 0; } -void Gsu::PeekBlock(uint32_t addr, uint8_t *output) +void Gsu::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo Gsu::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } -void Gsu::Serialize(Serializer &s) +void Gsu::Serialize(Serializer& s) { s.Stream( _state.CycleCount, _state.RegisterLatch, _state.ProgramBank, _state.RomBank, _state.RamBank, _state.IrqDisabled, - _state.HighSpeedMode, _state.ClockSelect, _state.BackupRamEnabled, _state.ScreenBase, _state.ColorGradient, _state.PlotBpp, - _state.ScreenHeight, _state.GsuRamAccess, _state.GsuRomAccess, _state.CacheBase, _state.PlotTransparent, _state.PlotDither, + _state.HighSpeedMode, _state.ClockSelect, _state.BackupRamEnabled, _state.ScreenBase, _state.ColorGradient, + _state.PlotBpp, + _state.ScreenHeight, _state.GsuRamAccess, _state.GsuRomAccess, _state.CacheBase, _state.PlotTransparent, + _state.PlotDither, _state.ColorHighNibble, _state.ColorFreezeHigh, _state.ObjMode, _state.ColorReg, _state.SrcReg, _state.DestReg, - _state.RomReadBuffer, _state.RomDelay, _state.ProgramReadBuffer, _state.RamWriteAddress, _state.RamWriteValue, _state.RamDelay, - _state.RamAddress, _state.PrimaryCache.X, _state.PrimaryCache.Y, _state.PrimaryCache.ValidBits, _state.SecondaryCache.X, + _state.RomReadBuffer, _state.RomDelay, _state.ProgramReadBuffer, _state.RamWriteAddress, _state.RamWriteValue, + _state.RamDelay, + _state.RamAddress, _state.PrimaryCache.X, _state.PrimaryCache.Y, _state.PrimaryCache.ValidBits, + _state.SecondaryCache.X, _state.SecondaryCache.Y, _state.SecondaryCache.ValidBits, - _state.SFR.Alt1, _state.SFR.Alt2, _state.SFR.Carry, _state.SFR.ImmHigh, _state.SFR.ImmLow, _state.SFR.Irq, _state.SFR.Overflow, + _state.SFR.Alt1, _state.SFR.Alt2, _state.SFR.Carry, _state.SFR.ImmHigh, _state.SFR.ImmLow, _state.SFR.Irq, + _state.SFR.Overflow, _state.SFR.Prefix, _state.SFR.RomReadPending, _state.SFR.Running, _state.SFR.Sign, _state.SFR.Zero ); @@ -672,12 +1026,14 @@ void Gsu::SetReg(GsuRegister reg, uint16_t value) case GsuRegister::GsuRegD: case GsuRegister::GsuRegE: case GsuRegister::GsuRegF: - { - _state.R[static_cast(reg) & 0xF] = value; - } break; + { + _state.R[static_cast(reg) & 0xF] = value; + } + break; case GsuRegister::GsuRegSFR: - { - _state.SFR.SetFlags(value); - } break; + { + _state.SFR.SetFlags(value); + } + break; } } diff --git a/Core/Gsu.h b/Core/Gsu.h index 744760b..03c4941 100644 --- a/Core/Gsu.h +++ b/Core/Gsu.h @@ -13,10 +13,10 @@ class EmuSettings; class Gsu : public BaseCoprocessor { private: - Console *_console; - MemoryManager *_memoryManager; - Cpu *_cpu; - EmuSettings *_settings; + Console* _console; + MemoryManager* _memoryManager; + Cpu* _cpu; + EmuSettings* _settings; uint8_t _clockMultiplier; GsuState _state; @@ -41,7 +41,7 @@ private: void InitProgramCache(uint16_t cacheAddr); - uint8_t ReadOperand(); + uint8_t ReadOperand(); uint8_t ReadOpCode(); uint8_t ReadProgramByte(MemoryOperationType opType); @@ -51,7 +51,7 @@ private: void ResetFlags(); void InvalidateCache(); - + void WaitRomOperation(); void WaitRamOperation(); @@ -69,7 +69,7 @@ private: void CACHE(); void Branch(bool branch); - + void BRA(); void BLT(); void BGE(); @@ -108,7 +108,7 @@ private: bool IsTransparentPixel(); void DrawPixel(uint8_t x, uint8_t y); void FlushPrimaryCache(uint8_t x, uint8_t y); - void WritePixelCache(GsuPixelCache &cache); + void WritePixelCache(GsuPixelCache& cache); uint8_t GetColor(uint8_t source); @@ -144,7 +144,7 @@ private: void GETB(); public: - Gsu(Console *console, uint32_t gsuRamSize); + Gsu(Console* console, uint32_t gsuRamSize); virtual ~Gsu(); void ProcessEndOfFrame() override; @@ -154,17 +154,17 @@ public: void LoadBattery() override; void SaveBattery() override; - + void Run() override; void Reset() override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; GsuState GetState(); MemoryMappings* GetMemoryMappings(); @@ -172,4 +172,4 @@ public: uint32_t DebugGetWorkRamSize(); void SetReg(GsuRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/GsuDebugger.cpp b/Core/GsuDebugger.cpp index 9d34ccb..1d11a38 100644 --- a/Core/GsuDebugger.cpp +++ b/Core/GsuDebugger.cpp @@ -37,24 +37,29 @@ void GsuDebugger::Reset() void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) { - if(type == MemoryOperationType::DummyRead) { + if (type == MemoryOperationType::DummyRead) + { //Ignore all dummy reads for now return; } AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; - if(type == MemoryOperationType::ExecOpCode) { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + if (type == MemoryOperationType::ExecOpCode) + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Gsu); } - if(_traceLogger->IsCpuLogged(CpuType::Gsu) || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) { + if (_traceLogger->IsCpuLogged(CpuType::Gsu) || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) + { GsuState gsuState = _gsu->GetState(); _disassembler->BuildCache(addressInfo, gsuState.SFR.GetFlagsHigh() & 0x13, CpuType::Gsu); - if(_traceLogger->IsCpuLogged(CpuType::Gsu)) { + if (_traceLogger->IsCpuLogged(CpuType::Gsu)) + { DebugState debugState; _debugger->GetState(debugState, true); debugState.Gsu.R[15] = addr; @@ -67,12 +72,16 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType _prevOpCode = value; _prevProgramCounter = addr; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + } + else + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Gsu); } _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); @@ -84,7 +93,7 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); _disassembler->InvalidateCache(addressInfo, CpuType::Gsu); @@ -100,14 +109,16 @@ void GsuDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::StepOut: - case StepType::StepOver: - case StepType::Step: step.StepCount = stepCount; break; - - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + switch (type) + { + case StepType::StepOut: + case StepType::StepOver: + case StepType::Step: step.StepCount = stepCount; + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -116,4 +127,4 @@ void GsuDebugger::Step(int32_t stepCount, StepType type) BreakpointManager* GsuDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/GsuDebugger.h b/Core/GsuDebugger.h index b07951a..53c7cdc 100644 --- a/Core/GsuDebugger.h +++ b/Core/GsuDebugger.h @@ -41,4 +41,4 @@ public: void Step(int32_t stepCount, StepType type); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/GsuDisUtils.cpp b/Core/GsuDisUtils.cpp index b5473ee..a01f756 100644 --- a/Core/GsuDisUtils.cpp +++ b/Core/GsuDisUtils.cpp @@ -6,9 +6,12 @@ #include "../Utilities/FastString.h" #include "../Utilities/HexUtilities.h" -void GsuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings *settings) +void GsuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { - constexpr const char* registerNames[16] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; + constexpr const char* registerNames[16] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" + }; bool alt1 = (info.GetFlags() & 0x01) != 0; bool alt2 = (info.GetFlags() & 0x02) != 0; bool prefix = (info.GetFlags() & 0x10) != 0; @@ -17,194 +20,468 @@ void GsuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - auto getJumpTarget = [&str, labelManager, memoryAddr, &info]() { + auto getJumpTarget = [&str, labelManager, memoryAddr, &info]() + { uint32_t jmpTarget = memoryAddr + (int8_t)info.GetByteCode()[1] + 2; - AddressInfo address = { (int32_t)jmpTarget, SnesMemoryType::GsuMemory }; + AddressInfo address = {(int32_t)jmpTarget, SnesMemoryType::GsuMemory}; string label = labelManager->GetLabel(address); - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex24(jmpTarget)); - } else { + } + else + { str.Write(label, true); } }; const char* reg = registerNames[opCode & 0x0F]; - switch(opCode) { - case 0x00: str.Write("STOP"); break; - case 0x01: str.Write("NOP"); break; - case 0x02: str.Write("CACHE"); break; - case 0x03: str.Write("LSR"); break; - case 0x04: str.Write("ROL"); break; - - case 0x05: str.WriteAll("BRA "); getJumpTarget(); break; - case 0x06: str.WriteAll("BLT "); getJumpTarget(); break; - case 0x07: str.WriteAll("BGE "); getJumpTarget(); break; - case 0x08: str.WriteAll("BNE "); getJumpTarget(); break; - case 0x09: str.WriteAll("BEQ "); getJumpTarget(); break; - case 0x0A: str.WriteAll("BPL "); getJumpTarget(); break; - case 0x0B: str.WriteAll("BMI "); getJumpTarget(); break; - case 0x0C: str.WriteAll("BCC "); getJumpTarget(); break; - case 0x0D: str.WriteAll("BCS "); getJumpTarget(); break; - case 0x0E: str.WriteAll("BCV "); getJumpTarget(); break; - case 0x0F: str.WriteAll("BVS "); getJumpTarget(); break; + switch (opCode) + { + case 0x00: str.Write("STOP"); + break; + case 0x01: str.Write("NOP"); + break; + case 0x02: str.Write("CACHE"); + break; + case 0x03: str.Write("LSR"); + break; + case 0x04: str.Write("ROL"); + break; - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: - str.WriteAll(prefix ? "MOVE R" : "TO R", reg); - break; + case 0x05: str.WriteAll("BRA "); + getJumpTarget(); + break; + case 0x06: str.WriteAll("BLT "); + getJumpTarget(); + break; + case 0x07: str.WriteAll("BGE "); + getJumpTarget(); + break; + case 0x08: str.WriteAll("BNE "); + getJumpTarget(); + break; + case 0x09: str.WriteAll("BEQ "); + getJumpTarget(); + break; + case 0x0A: str.WriteAll("BPL "); + getJumpTarget(); + break; + case 0x0B: str.WriteAll("BMI "); + getJumpTarget(); + break; + case 0x0C: str.WriteAll("BCC "); + getJumpTarget(); + break; + case 0x0D: str.WriteAll("BCS "); + getJumpTarget(); + break; + case 0x0E: str.WriteAll("BCV "); + getJumpTarget(); + break; + case 0x0F: str.WriteAll("BVS "); + getJumpTarget(); + break; - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: - str.WriteAll("WITH R", reg); - break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + str.WriteAll(prefix ? "MOVE R" : "TO R", reg); + break; - case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3A: case 0x3B: - str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')'); - break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + str.WriteAll("WITH R", reg); + break; - case 0x3C: str.Write("LOOP"); break; - case 0x3D: str.Write("ALT1"); break; - case 0x3E: str.Write("ALT2"); break; - case 0x3F: str.Write("ALT3"); break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')'); + break; - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4A: case 0x4B: - str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')'); - break; + case 0x3C: str.Write("LOOP"); + break; + case 0x3D: str.Write("ALT1"); + break; + case 0x3E: str.Write("ALT2"); + break; + case 0x3F: str.Write("ALT3"); + break; - case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT"); break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')'); + break; - case 0x4D: str.Write("SWAP"); break; - case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR"); break; + case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT"); + break; - case 0x4F: str.Write("NOT"); break; + case 0x4D: str.Write("SWAP"); + break; + case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR"); + break; - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: - str.Write(alt1 ? "ADC " : "ADD "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; + case 0x4F: str.Write("NOT"); + break; - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: - if(alt2 && alt1) { - str.WriteAll("CMP R", reg); - } else { - if(!alt2 && alt1) { - str.Write("SBC "); - } else { - str.Write("SUB "); - } - if(alt2 && !alt1) { - str.WriteAll('#', reg); - } else { - str.WriteAll('R', reg); - } + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + str.Write(alt1 ? "ADC " : "ADD "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + if (alt2 && alt1) + { + str.WriteAll("CMP R", reg); + } + else + { + if (!alt2 && alt1) + { + str.Write("SBC "); } - break; - - case 0x70: str.Write("MERGE"); break; - - case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - str.Write(alt1 ? "BIC " : "AND "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: - str.Write(alt1 ? "UMULT " : "MULT "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0x90: str.Write("SBK"); break; - - case 0x91: case 0x92: case 0x93: case 0x94: - str.WriteAll("LINK #", reg); - break; - - case 0x95: str.Write("SEX"); break; - - case 0x96: str.Write(alt1 ? "DIV2" : "ASR"); break; - case 0x97: str.Write("ROR"); break; - - case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: - str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg); - break; - - case 0x9E: str.Write("LOB"); break; - case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT"); break; - - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - if(alt1) { - str.WriteAll("LMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); - } else if(alt2) { - str.WriteAll("SMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); - } else { - str.WriteAll("IBT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[1])); + else + { + str.Write("SUB "); } - break; - - case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: - case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: - str.WriteAll(prefix ? "MOVES R" : "FROM R", reg); - break; - - case 0xC0: str.Write("HIB"); break; - - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: - case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: - str.Write(alt1 ? "XOR " : "OR "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: - case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: - str.WriteAll("INC R", reg); - break; - - case 0xDF: - if(!alt2) { - //GETC - "Get byte from ROM to color register" - str.Write("GETC"); - } else if(!alt1) { - //RAMB - "Set RAM data bank" - str.Write("RAMB"); - } else { - str.Write("ROMB"); + if (alt2 && !alt1) + { + str.WriteAll('#', reg); } - break; - - case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: - case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: - str.WriteAll("DEC R", reg); - break; - - case 0xEF: - if(alt2 && alt1) { - str.Write("GETBS"); - } else if(alt2) { - str.Write("GETBL"); - } else if(alt1) { - str.Write("GETBH"); - } else { - str.Write("GETB"); + else + { + str.WriteAll('R', reg); } - break; + } + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - if(alt1) { - str.WriteAll("LM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); - } else if(alt2) { - str.WriteAll("SM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); - } else { - str.WriteAll("IWT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1])); - } - break; + case 0x70: str.Write("MERGE"); + break; + + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + str.Write(alt1 ? "BIC " : "AND "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + str.Write(alt1 ? "UMULT " : "MULT "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x90: str.Write("SBK"); + break; + + case 0x91: + case 0x92: + case 0x93: + case 0x94: + str.WriteAll("LINK #", reg); + break; + + case 0x95: str.Write("SEX"); + break; + + case 0x96: str.Write(alt1 ? "DIV2" : "ASR"); + break; + case 0x97: str.Write("ROR"); + break; + + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg); + break; + + case 0x9E: str.Write("LOB"); + break; + case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT"); + break; + + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + if (alt1) + { + str.WriteAll("LMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } + else if (alt2) + { + str.WriteAll("SMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } + else + { + str.WriteAll("IBT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; + + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + str.WriteAll(prefix ? "MOVES R" : "FROM R", reg); + break; + + case 0xC0: str.Write("HIB"); + break; + + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + str.Write(alt1 ? "XOR " : "OR "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + str.WriteAll("INC R", reg); + break; + + case 0xDF: + if (!alt2) + { + //GETC - "Get byte from ROM to color register" + str.Write("GETC"); + } + else if (!alt1) + { + //RAMB - "Set RAM data bank" + str.Write("RAMB"); + } + else + { + str.Write("ROMB"); + } + break; + + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + str.WriteAll("DEC R", reg); + break; + + case 0xEF: + if (alt2 && alt1) + { + str.Write("GETBS"); + } + else if (alt2) + { + str.Write("GETBL"); + } + else if (alt1) + { + str.Write("GETBH"); + } + else + { + str.Write("GETB"); + } + break; + + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + if (alt1) + { + str.WriteAll("LM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } + else if (alt2) + { + str.WriteAll("SM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } + else + { + str.WriteAll("IWT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; } out += str.ToString(); @@ -216,20 +493,51 @@ int32_t GsuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console bool alt1 = (info.GetFlags() & 0x01) != 0; bool alt2 = (info.GetFlags() & 0x02) != 0; - switch(opCode) { - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - if(alt1 || alt2) { - return 0x700000 | (info.GetByteCode()[1] << 1) | (state.RamBank << 16); - } - break; + switch (opCode) + { + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + if (alt1 || alt2) + { + return 0x700000 | (info.GetByteCode()[1] << 1) | (state.RamBank << 16); + } + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - if(alt1 || alt2) { - return 0x700000 | info.GetByteCode()[1] | (info.GetByteCode()[2] << 8) | (state.RamBank << 16); - } - break; + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + if (alt1 || alt2) + { + return 0x700000 | info.GetByteCode()[1] | (info.GetByteCode()[2] << 8) | (state.RamBank << 16); + } + break; } return -1; diff --git a/Core/GsuDisUtils.h b/Core/GsuDisUtils.h index 47ea54e..d8aa52a 100644 --- a/Core/GsuDisUtils.h +++ b/Core/GsuDisUtils.h @@ -10,6 +10,7 @@ struct GsuState; class GsuDisUtils { 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, GsuState& state); }; diff --git a/Core/GsuRamHandler.h b/Core/GsuRamHandler.h index 01daec8..890ce6e 100644 --- a/Core/GsuRamHandler.h +++ b/Core/GsuRamHandler.h @@ -6,11 +6,11 @@ class GsuRamHandler : public IMemoryHandler { private: - GsuState *_state; - IMemoryHandler *_handler; + GsuState* _state; + IMemoryHandler* _handler; public: - GsuRamHandler(GsuState &state, IMemoryHandler *handler) : IMemoryHandler(SnesMemoryType::GsuWorkRam) + GsuRamHandler(GsuState& state, IMemoryHandler* handler) : IMemoryHandler(SnesMemoryType::GsuWorkRam) { _handler = handler; _state = &state; @@ -18,7 +18,8 @@ public: uint8_t Read(uint32_t addr) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { return _handler->Read(addr); } @@ -31,26 +32,31 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = Read(i); } } void Write(uint32_t addr, uint8_t value) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { _handler->Write(addr, value); } } AddressInfo GetAbsoluteAddress(uint32_t address) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { return _handler->GetAbsoluteAddress(address); - } else { - return { -1, SnesMemoryType::Register }; + } + else + { + return {-1, SnesMemoryType::Register}; } } -}; \ No newline at end of file +}; diff --git a/Core/GsuRomHandler.h b/Core/GsuRomHandler.h index cf6b0e0..1222b99 100644 --- a/Core/GsuRomHandler.h +++ b/Core/GsuRomHandler.h @@ -6,11 +6,11 @@ class GsuRomHandler : public IMemoryHandler { private: - GsuState *_state; - IMemoryHandler *_romHandler; + GsuState* _state; + IMemoryHandler* _romHandler; public: - GsuRomHandler(GsuState &state, IMemoryHandler *romHandler) : IMemoryHandler(SnesMemoryType::PrgRom) + GsuRomHandler(GsuState& state, IMemoryHandler* romHandler) : IMemoryHandler(SnesMemoryType::PrgRom) { _romHandler = romHandler; _state = &state; @@ -18,22 +18,28 @@ public: uint8_t Read(uint32_t addr) override { - if(!_state->SFR.Running || !_state->GsuRomAccess) { + if (!_state->SFR.Running || !_state->GsuRomAccess) + { return _romHandler->Read(addr); } - if(addr & 0x01) { + if (addr & 0x01) + { return 0x01; } - switch(addr & 0x0E) { - default: - case 2: case 6: case 8: case 0x0C: - return 0; + switch (addr & 0x0E) + { + default: + case 2: + case 6: + case 8: + case 0x0C: + return 0; - case 4: return 0x04; - case 0x0A: return 0x08; - case 0x0E: return 0x0C; + case 4: return 0x04; + case 0x0A: return 0x08; + case 0x0E: return 0x0C; } } @@ -42,9 +48,10 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = Read(i); } } @@ -56,10 +63,13 @@ public: AddressInfo GetAbsoluteAddress(uint32_t address) override { - if(!_state->SFR.Running || !_state->GsuRomAccess) { + if (!_state->SFR.Running || !_state->GsuRomAccess) + { return _romHandler->GetAbsoluteAddress(address); - } else { - return { -1, SnesMemoryType::Register }; + } + else + { + return {-1, SnesMemoryType::Register}; } } -}; \ No newline at end of file +}; diff --git a/Core/GsuTypes.h b/Core/GsuTypes.h index 2dabec2..0a1be6c 100644 --- a/Core/GsuTypes.h +++ b/Core/GsuTypes.h @@ -15,7 +15,7 @@ struct GsuFlags bool ImmHigh; bool Prefix; bool Irq; - + uint8_t GetFlagsLow() { return ( @@ -77,7 +77,7 @@ struct GsuState uint16_t R[16]; GsuFlags SFR; - + uint8_t RegisterLatch; uint8_t ProgramBank; @@ -89,7 +89,7 @@ struct GsuState bool ClockSelect; bool BackupRamEnabled; uint8_t ScreenBase; - + uint8_t ColorGradient; uint8_t PlotBpp; uint8_t ScreenHeight; @@ -107,7 +107,7 @@ struct GsuState uint8_t ColorReg; uint8_t SrcReg; uint8_t DestReg; - + uint8_t RomReadBuffer; uint8_t RomDelay; @@ -118,7 +118,7 @@ struct GsuState uint8_t RamDelay; uint16_t RamAddress; - + GsuPixelCache PrimaryCache; GsuPixelCache SecondaryCache; -}; \ No newline at end of file +}; diff --git a/Core/HandShakeMessage.h b/Core/HandShakeMessage.h index c60bdf6..ec4abb0 100644 --- a/Core/HandShakeMessage.h +++ b/Core/HandShakeMessage.h @@ -14,15 +14,18 @@ private: bool _spectator = false; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_emuVersion, _protocolVersion, _playerName, _hashedPassword, _spectator); } public: - HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {} + HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } - HandShakeMessage(string playerName, string hashedPassword, bool spectator, uint32_t emuVersion) : NetMessage(MessageType::HandShake) + HandShakeMessage(string playerName, string hashedPassword, bool spectator, uint32_t emuVersion) : NetMessage( + MessageType::HandShake) { _emuVersion = emuVersion; _protocolVersion = HandShakeMessage::CurrentVersion; @@ -54,7 +57,8 @@ public: static string GetPasswordHash(string serverPassword, string connectionHash) { string saltedPassword = serverPassword + connectionHash; - vector dataToHash = vector(saltedPassword.c_str(), saltedPassword.c_str() + saltedPassword.size()); + vector dataToHash = vector(saltedPassword.c_str(), + saltedPassword.c_str() + saltedPassword.size()); return SHA1::GetHash(dataToHash); } }; diff --git a/Core/HistoryViewer.cpp b/Core/HistoryViewer.cpp index cbe2993..d24e9ed 100644 --- a/Core/HistoryViewer.cpp +++ b/Core/HistoryViewer.cpp @@ -39,12 +39,15 @@ uint32_t HistoryViewer::GetHistoryLength() void HistoryViewer::GetHistorySegments(uint32_t* segmentBuffer, uint32_t& bufferSize) { uint32_t segmentIndex = 0; - for (size_t i = 0; i < _history.size(); i++) { - if (_history[i].EndOfSegment) { + for (size_t i = 0; i < _history.size(); i++) + { + if (_history[i].EndOfSegment) + { segmentBuffer[segmentIndex] = (uint32_t)i; segmentIndex++; - if (segmentIndex == bufferSize) { + if (segmentIndex == bufferSize) + { //Reached buffer size, can't return any more values break; } @@ -61,7 +64,8 @@ uint32_t HistoryViewer::GetPosition() void HistoryViewer::SeekTo(uint32_t seekPosition) { //Seek to the specified position - if (seekPosition < _history.size()) { + if (seekPosition < _history.size()) + { _console->Lock(); bool wasPaused = _console->IsPaused(); @@ -73,7 +77,8 @@ void HistoryViewer::SeekTo(uint32_t seekPosition) _console->GetSoundMixer()->StopAudio(true); _pollCounter = 0; - if (wasPaused) { + if (wasPaused) + { _console->Pause(); } @@ -83,13 +88,15 @@ void HistoryViewer::SeekTo(uint32_t seekPosition) bool HistoryViewer::CreateSaveState(string outputFile, uint32_t position) { - if (position < _history.size()) { + if (position < _history.size()) + { std::stringstream stateData; _console->GetSaveStateManager()->GetSaveStateHeader(stateData); _history[position].GetStateData(stateData); ofstream output(outputFile, ios::binary); - if (output) { + if (output) + { output << stateData.rdbuf(); output.close(); return true; @@ -120,16 +127,19 @@ bool HistoryViewer::SaveMovie(string movieFile, uint32_t startPosition, uint32_t void HistoryViewer::ResumeGameplay(shared_ptr console, uint32_t resumePosition) { console->Lock(); - if (_console->GetRomInfo().RomFile.GetSha1Hash() != console->GetRomInfo().RomFile.GetSha1Hash()) { + if (_console->GetRomInfo().RomFile.GetSha1Hash() != console->GetRomInfo().RomFile.GetSha1Hash()) + { //Load game on the main window if they aren't the same console->LoadRom(console->GetRomInfo().RomFile, console->GetRomInfo().PatchFile); // Mesen does console->Initialize(_console->GetRomPath(), _console->GetPatchFile()); // but that's probably equivalent } - if (resumePosition < _history.size()) { + if (resumePosition < _history.size()) + { _history[resumePosition].LoadState(console); } - else { + else + { _history[_history.size() - 1].LoadState(console); } console->Unlock(); @@ -137,16 +147,18 @@ void HistoryViewer::ResumeGameplay(shared_ptr console, uint32_t resumeP bool HistoryViewer::SetInput(BaseControlDevice* device) { - uint8_t port = device->GetPort(); - if (_position < _history.size()) { + if (_position < _history.size()) + { std::deque& stateData = _history[_position].InputLogs[port]; - if (_pollCounter < stateData.size()) { + if (_pollCounter < stateData.size()) + { ControlDeviceState state = stateData[_pollCounter]; device->SetRawState(state); } } - if (port == 0 && _pollCounter < HistoryViewer::BufferSize) { + if (port == 0 && _pollCounter < HistoryViewer::BufferSize) + { _pollCounter++; } return true; @@ -154,11 +166,13 @@ bool HistoryViewer::SetInput(BaseControlDevice* device) void HistoryViewer::ProcessEndOfFrame() { - if (_pollCounter == HistoryViewer::BufferSize) { + if (_pollCounter == HistoryViewer::BufferSize) + { _pollCounter = 0; _position++; - if (_position >= _history.size()) { + if (_position >= _history.size()) + { //Reached the end of history data _console->Pause(); return; diff --git a/Core/HistoryViewer.h b/Core/HistoryViewer.h index 5340ecc..e06a49c 100644 --- a/Core/HistoryViewer.h +++ b/Core/HistoryViewer.h @@ -36,4 +36,4 @@ public: // Inherited via IInputProvider bool SetInput(BaseControlDevice* device) override; -}; \ No newline at end of file +}; diff --git a/Core/IAudioDevice.h b/Core/IAudioDevice.h index b371bfd..babbaad 100644 --- a/Core/IAudioDevice.h +++ b/Core/IAudioDevice.h @@ -12,8 +12,11 @@ struct AudioStatistics class IAudioDevice { public: - virtual ~IAudioDevice() {} - virtual void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0; + virtual ~IAudioDevice() + { + } + + virtual void PlayBuffer(int16_t* soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0; virtual void Stop() = 0; virtual void Pause() = 0; virtual void ProcessEndOfFrame() = 0; @@ -22,4 +25,4 @@ public: virtual void SetAudioDevice(string deviceName) = 0; virtual AudioStatistics GetStatistics() = 0; -}; \ No newline at end of file +}; diff --git a/Core/IDebugger.h b/Core/IDebugger.h index 0fc3384..60379e2 100644 --- a/Core/IDebugger.h +++ b/Core/IDebugger.h @@ -7,4 +7,4 @@ class IDebugger { public: virtual void Step(int32_t stepCount, StepType type) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IInputProvider.h b/Core/IInputProvider.h index d4dbab8..6f7f9d1 100644 --- a/Core/IInputProvider.h +++ b/Core/IInputProvider.h @@ -6,4 +6,4 @@ class IInputProvider { public: virtual bool SetInput(BaseControlDevice* device) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IInputRecorder.h b/Core/IInputRecorder.h index 3e7195d..866d94d 100644 --- a/Core/IInputRecorder.h +++ b/Core/IInputRecorder.h @@ -7,4 +7,4 @@ class IInputRecorder { public: virtual void RecordInput(vector> devices) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IKeyManager.h b/Core/IKeyManager.h index c9eed5b..0078078 100644 --- a/Core/IKeyManager.h +++ b/Core/IKeyManager.h @@ -23,7 +23,9 @@ struct MouseMovement class IKeyManager { public: - virtual ~IKeyManager() {} + virtual ~IKeyManager() + { + } virtual void RefreshState() = 0; virtual void UpdateDevices() = 0; @@ -36,4 +38,4 @@ public: virtual void SetKeyState(uint16_t scanCode, bool state) = 0; virtual void ResetKeyState() = 0; virtual void SetDisabled(bool disabled) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h index 63bb64f..a9ce13e 100644 --- a/Core/IMemoryHandler.h +++ b/Core/IMemoryHandler.h @@ -13,11 +13,13 @@ public: _memoryType = memType; } - virtual ~IMemoryHandler() {} + virtual ~IMemoryHandler() + { + } virtual uint8_t Read(uint32_t addr) = 0; virtual uint8_t Peek(uint32_t addr) = 0; - virtual void PeekBlock(uint32_t addr, uint8_t *output) = 0; + virtual void PeekBlock(uint32_t addr, uint8_t* output) = 0; virtual void Write(uint32_t addr, uint8_t value) = 0; __forceinline SnesMemoryType GetMemoryType() @@ -26,4 +28,4 @@ public: } virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IMessageManager.h b/Core/IMessageManager.h index 1069a17..a37212c 100644 --- a/Core/IMessageManager.h +++ b/Core/IMessageManager.h @@ -21,7 +21,8 @@ private: uint64_t GetCurrentTime() { - return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + return std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } public: @@ -38,7 +39,7 @@ public: return _title; } - string GetToastMessage() + string GetToastMessage() { return _message; } @@ -46,13 +47,20 @@ public: float GetOpacity() { uint64_t currentTime = GetCurrentTime(); - if(currentTime - _startTime < 200) { + if (currentTime - _startTime < 200) + { return (currentTime - _startTime) * 5.0f / 1000.0f; - } else if(_endTime - currentTime < 200) { + } + else if (_endTime - currentTime < 200) + { return (_endTime - currentTime) * 5.0f / 1000.0f; - } else if(currentTime >= _endTime) { + } + else if (currentTime >= _endTime) + { return 0.0f; - } else { + } + else + { return 1.0f; } } @@ -61,4 +69,4 @@ public: { return _endTime < GetCurrentTime(); } -}; \ No newline at end of file +}; diff --git a/Core/INotificationListener.h b/Core/INotificationListener.h index 21bcbbc..d2e7fad 100644 --- a/Core/INotificationListener.h +++ b/Core/INotificationListener.h @@ -26,4 +26,4 @@ class INotificationListener { public: virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IRenderingDevice.h b/Core/IRenderingDevice.h index a8612ea..0c0559c 100644 --- a/Core/IRenderingDevice.h +++ b/Core/IRenderingDevice.h @@ -4,10 +4,14 @@ class IRenderingDevice { - public: - virtual ~IRenderingDevice() {} - virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) = 0; - virtual void Render() = 0; - virtual void Reset() = 0; - virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0; -}; \ No newline at end of file +public: + virtual ~IRenderingDevice() + { + } + + virtual void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) = 0; + virtual void Render() = 0; + virtual void Reset() = 0; + virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = + 0; +}; diff --git a/Core/InputDataMessage.h b/Core/InputDataMessage.h index 4957bf5..9bc4da9 100644 --- a/Core/InputDataMessage.h +++ b/Core/InputDataMessage.h @@ -8,14 +8,16 @@ class InputDataMessage : public NetMessage private: ControlDeviceState _inputState; -protected: - void Serialize(Serializer &s) override +protected: + void Serialize(Serializer& s) override { s.StreamVector(_inputState.State); } public: - InputDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + InputDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } InputDataMessage(ControlDeviceState inputState) : NetMessage(MessageType::InputData) { @@ -26,4 +28,4 @@ public: { return _inputState; } -}; \ No newline at end of file +}; diff --git a/Core/InputHud.cpp b/Core/InputHud.cpp index 93224c1..e70879a 100644 --- a/Core/InputHud.cpp +++ b/Core/InputHud.cpp @@ -10,7 +10,7 @@ #include "DebugHud.h" #include "ControlManager.h" -static constexpr int color[2] = { 0x00111111, 0x00FFFFFF }; +static constexpr int color[2] = {0x00111111, 0x00FFFFFF}; InputHud::InputHud(Console* console) { @@ -19,71 +19,83 @@ InputHud::InputHud(Console* console) void InputHud::DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber) { - SnesController controller(_console, 0, KeyMappingSet()); controller.SetRawState(state); shared_ptr hud = _console->GetDebugHud(); hud->DrawRectangle(0 + x, 0 + y, 35, 14, 0x80CCCCCC, true, 1, frameNumber); hud->DrawRectangle(0 + x, 0 + y, 35, 14, color[0], false, 1, frameNumber); - hud->DrawRectangle(5 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Up)], true, 1, frameNumber); - hud->DrawRectangle(5 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Down)], true, 1, frameNumber); - hud->DrawRectangle(2 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Left)], true, 1, frameNumber); - hud->DrawRectangle(8 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Right)], true, 1, frameNumber); + hud->DrawRectangle(5 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Up)], true, 1, + frameNumber); + hud->DrawRectangle(5 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Down)], true, 1, + frameNumber); + hud->DrawRectangle(2 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Left)], true, 1, + frameNumber); + hud->DrawRectangle(8 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Right)], true, 1, + frameNumber); hud->DrawRectangle(5 + x, 6 + y, 3, 3, color[0], true, 1, frameNumber); - hud->DrawRectangle(27 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::X)], true, 1, frameNumber); - hud->DrawRectangle(27 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::B)], true, 1, frameNumber); - hud->DrawRectangle(30 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::A)], true, 1, frameNumber); - hud->DrawRectangle(24 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Y)], true, 1, frameNumber); + hud->DrawRectangle(27 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::X)], true, 1, + frameNumber); + hud->DrawRectangle(27 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::B)], true, 1, + frameNumber); + hud->DrawRectangle(30 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::A)], true, 1, + frameNumber); + hud->DrawRectangle(24 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Y)], true, 1, + frameNumber); - hud->DrawRectangle(4 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::L)], true, 1, frameNumber); - hud->DrawRectangle(26 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::R)], true, 1, frameNumber); + hud->DrawRectangle(4 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::L)], true, 1, + frameNumber); + hud->DrawRectangle(26 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::R)], true, 1, + frameNumber); - hud->DrawRectangle(13 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Select)], true, 1, frameNumber); - hud->DrawRectangle(18 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Start)], true, 1, frameNumber); + hud->DrawRectangle(13 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Select)], true, 1, + frameNumber); + hud->DrawRectangle(18 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Start)], true, 1, + frameNumber); - switch(port) { - case 0: - //1 - hud->DrawLine(17 + x, 2 + y, 17 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); - break; + switch (port) + { + case 0: + //1 + hud->DrawLine(17 + x, 2 + y, 17 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); + break; - case 1: - //2 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 1: + //2 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; - case 2: - //3 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 2: + //3 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; - case 3: - //4 - hud->DrawLine(16 + x, 2 + y, 16 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawLine(18 + x, 2 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - break; + case 3: + //4 + hud->DrawLine(16 + x, 2 + y, 16 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawLine(18 + x, 2 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + break; - case 4: - //5 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 4: + //5 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; } } @@ -97,66 +109,80 @@ void InputHud::DrawControllers(OverscanDimensions overscan, int frameNumber) int xOffset = cfg.DisplayInputHorizontally ? 38 : 0; int yOffset = cfg.DisplayInputHorizontally ? 0 : 16; - switch(cfg.DisplayInputPosition) { - default: - case InputDisplayPosition::TopLeft: - xStart = overscan.Left + 3; - yStart = overscan.Top + 3; - break; - case InputDisplayPosition::TopRight: - xStart = 256 - overscan.Right - 38; - yStart = overscan.Top + 3; - xOffset = -xOffset; - break; - case InputDisplayPosition::BottomLeft: - xStart = overscan.Left + 3; - yStart = 240 - overscan.Bottom - 18; - yOffset = -yOffset; - break; - case InputDisplayPosition::BottomRight: - xStart = 256 - overscan.Right - 38; - yStart = 240 - overscan.Bottom - 18; - xOffset = -xOffset; - yOffset = -yOffset; - break; + switch (cfg.DisplayInputPosition) + { + default: + case InputDisplayPosition::TopLeft: + xStart = overscan.Left + 3; + yStart = overscan.Top + 3; + break; + case InputDisplayPosition::TopRight: + xStart = 256 - overscan.Right - 38; + yStart = overscan.Top + 3; + xOffset = -xOffset; + break; + case InputDisplayPosition::BottomLeft: + xStart = overscan.Left + 3; + yStart = 240 - overscan.Bottom - 18; + yOffset = -yOffset; + break; + case InputDisplayPosition::BottomRight: + xStart = 256 - overscan.Right - 38; + yStart = 240 - overscan.Bottom - 18; + xOffset = -xOffset; + yOffset = -yOffset; + break; } - for(int i = 0; i < (int)controllerData.size(); i++) { - if(controllerData[i].Type == ControllerType::SnesController) { - if(cfg.DisplayInputPort[i]) { + for (int i = 0; i < (int)controllerData.size(); i++) + { + if (controllerData[i].Type == ControllerType::SnesController) + { + if (cfg.DisplayInputPort[i]) + { DrawController(i, controllerData[i].State, xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } - } else if(controllerData[i].Type == ControllerType::Multitap) { + } + else if (controllerData[i].Type == ControllerType::Multitap) + { uint64_t rawData = 0; - for(int j = (int)controllerData[i].State.State.size() - 1; j >= 0; j--) { + for (int j = (int)controllerData[i].State.State.size() - 1; j >= 0; j--) + { rawData <<= 8; rawData |= controllerData[i].State.State[j]; } ControlDeviceState controllers[4] = {}; - for(int j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) + { controllers[j].State.push_back(rawData & 0xFF); controllers[j].State.push_back((rawData >> 8) & 0x0F); rawData >>= 12; } - if(cfg.DisplayInputPort[i]) { + if (cfg.DisplayInputPort[i]) + { DrawController(i, controllers[0], xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } - for(int j = 1; j < 4; j++) { - if(cfg.DisplayInputPort[j + 1]) { + for (int j = 1; j < 4; j++) + { + if (cfg.DisplayInputPort[j + 1]) + { DrawController(j + 1, controllers[j], xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } } - } else if(controllerData[i].Type == ControllerType::SuperScope) { - if(cfg.DisplayInputPort[i]) { + } + else if (controllerData[i].Type == ControllerType::SuperScope) + { + if (cfg.DisplayInputPort[i]) + { SuperScope scope(_console, 0, KeyMappingSet()); scope.SetRawState(controllerData[i].State); MousePosition pos = scope.GetCoordinates(); @@ -165,16 +191,21 @@ void InputHud::DrawControllers(OverscanDimensions overscan, int frameNumber) hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x00111111, true, 1, frameNumber); hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x80CCCCCC, false, 1, frameNumber); } - } else if(controllerData[i].Type == ControllerType::SnesMouse) { - if(cfg.DisplayInputPort[i]) { + } + else if (controllerData[i].Type == ControllerType::SnesMouse) + { + if (cfg.DisplayInputPort[i]) + { SnesMouse mouse(_console, 0); mouse.SetRawState(controllerData[i].State); shared_ptr hud = _console->GetDebugHud(); hud->DrawRectangle(xStart + 12, yStart, 11, 14, 0x00AAAAAA, true, 1, frameNumber); hud->DrawRectangle(xStart + 12, yStart, 11, 14, color[0], false, 1, frameNumber); - hud->DrawRectangle(xStart + 13, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Left)], true, 1, frameNumber); - hud->DrawRectangle(xStart + 18, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Right)], true, 1, frameNumber); + hud->DrawRectangle(xStart + 13, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Left)], true, 1, + frameNumber); + hud->DrawRectangle(xStart + 18, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Right)], true, + 1, frameNumber); xStart += xOffset; yStart += yOffset; diff --git a/Core/InputHud.h b/Core/InputHud.h index fb3f2e0..acb793f 100644 --- a/Core/InputHud.h +++ b/Core/InputHud.h @@ -13,7 +13,7 @@ private: void DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber); public: - InputHud(Console *console); + InputHud(Console* console); void DrawControllers(OverscanDimensions overscan, int frameNumber); -}; \ No newline at end of file +}; diff --git a/Core/InternalRegisters.cpp b/Core/InternalRegisters.cpp index 0cb41b2..5550274 100644 --- a/Core/InternalRegisters.cpp +++ b/Core/InternalRegisters.cpp @@ -44,7 +44,8 @@ void InternalRegisters::Reset() void InternalRegisters::ProcessAutoJoypadRead() { - if(!_state.EnableAutoJoypadRead) { + if (!_state.EnableAutoJoypadRead) + { return; } @@ -53,11 +54,13 @@ void InternalRegisters::ProcessAutoJoypadRead() controlManager->Write(0x4016, 1); controlManager->Write(0x4016, 0); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _state.ControllerData[i] = 0; } - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { uint8_t port1 = controlManager->Read(0x4016); uint8_t port2 = controlManager->Read(0x4017); @@ -86,142 +89,156 @@ void InternalRegisters::SetNmiFlag(bool nmiFlag) void InternalRegisters::SetIrqFlag(bool irqFlag) { _irqFlag = irqFlag && (_state.EnableHorizontalIrq || _state.EnableVerticalIrq); - if(_irqFlag) { + if (_irqFlag) + { _cpu->SetIrqSource(IrqSource::Ppu); - } else { + } + else + { _cpu->ClearIrqSource(IrqSource::Ppu); } } uint8_t InternalRegisters::Peek(uint16_t addr) { - switch(addr) { - case 0x4210: return (_nmiFlag ? 0x80 : 0) | 0x02; - case 0x4211: return (_irqFlag ? 0x80 : 0); - default: return Read(addr); + switch (addr) + { + case 0x4210: return (_nmiFlag ? 0x80 : 0) | 0x02; + case 0x4211: return (_irqFlag ? 0x80 : 0); + default: return Read(addr); } } uint8_t InternalRegisters::Read(uint16_t addr) { - switch(addr) { - case 0x4210: { + switch (addr) + { + case 0x4210: + { constexpr uint8_t cpuRevision = 0x02; - + uint8_t value = (_nmiFlag ? 0x80 : 0) | cpuRevision; //Reading $4210 on any cycle turns the NMI signal off (except presumably on the first PPU cycle (first 4 master clocks) of the NMI scanline.) //i.e: reading $4210 at the same it gets set will return it as set, and will keep it set. //Without this, Terranigma has corrupted sprites on some frames. - if(_memoryManager->GetHClock() >= 4 || _ppu->GetScanline() != _ppu->GetNmiScanline()) { + if (_memoryManager->GetHClock() >= 4 || _ppu->GetScanline() != _ppu->GetNmiScanline()) + { SetNmiFlag(false); } return value | (_memoryManager->GetOpenBus() & 0x70); } - case 0x4211: { + case 0x4211: + { uint8_t value = (_irqFlag ? 0x80 : 0); SetIrqFlag(false); return value | (_memoryManager->GetOpenBus() & 0x7F); } - case 0x4212: { + case 0x4212: + { uint16_t hClock = _memoryManager->GetHClock(); uint16_t scanline = _ppu->GetScanline(); uint16_t nmiScanline = _ppu->GetNmiScanline(); //TODO TIMING (set/clear timing) return ( (scanline >= nmiScanline ? 0x80 : 0) | - ((hClock >= 1*4 && hClock <= 274*4) ? 0 : 0x40) | - ((_state.EnableAutoJoypadRead && scanline >= nmiScanline && scanline <= nmiScanline + 2) ? 0x01 : 0) | //Auto joypad read in progress + ((hClock >= 1 * 4 && hClock <= 274 * 4) ? 0 : 0x40) | + ((_state.EnableAutoJoypadRead && scanline >= nmiScanline && scanline <= nmiScanline + 2) ? 0x01 : 0) | + //Auto joypad read in progress (_memoryManager->GetOpenBus() & 0x3E) ); } - case 0x4213: - //TODO RDIO - Programmable I/O port (in-port) - return 0; - - case 0x4214: - case 0x4215: - case 0x4216: - case 0x4217: - return _aluMulDiv.Read(addr); + case 0x4213: + //TODO RDIO - Programmable I/O port (in-port) + return 0; - case 0x4218: return (uint8_t)_state.ControllerData[0]; - case 0x4219: return (uint8_t)(_state.ControllerData[0] >> 8); - case 0x421A: return (uint8_t)_state.ControllerData[1]; - case 0x421B: return (uint8_t)(_state.ControllerData[1] >> 8); - case 0x421C: return (uint8_t)_state.ControllerData[2]; - case 0x421D: return (uint8_t)(_state.ControllerData[2] >> 8); - case 0x421E: return (uint8_t)_state.ControllerData[3]; - case 0x421F: return (uint8_t)(_state.ControllerData[3] >> 8); - - default: - LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); - return _memoryManager->GetOpenBus(); + case 0x4214: + case 0x4215: + case 0x4216: + case 0x4217: + return _aluMulDiv.Read(addr); + + case 0x4218: return (uint8_t)_state.ControllerData[0]; + case 0x4219: return (uint8_t)(_state.ControllerData[0] >> 8); + case 0x421A: return (uint8_t)_state.ControllerData[1]; + case 0x421B: return (uint8_t)(_state.ControllerData[1] >> 8); + case 0x421C: return (uint8_t)_state.ControllerData[2]; + case 0x421D: return (uint8_t)(_state.ControllerData[2] >> 8); + case 0x421E: return (uint8_t)_state.ControllerData[3]; + case 0x421F: return (uint8_t)(_state.ControllerData[3] >> 8); + + default: + LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); + return _memoryManager->GetOpenBus(); } } void InternalRegisters::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x4200: - _state.EnableNmi = (value & 0x80) != 0; - _state.EnableVerticalIrq = (value & 0x20) != 0; - _state.EnableHorizontalIrq = (value & 0x10) != 0; - _state.EnableAutoJoypadRead = (value & 0x01) != 0; - - SetNmiFlag(_nmiFlag); - SetIrqFlag(_irqFlag); - break; + switch (addr) + { + case 0x4200: + _state.EnableNmi = (value & 0x80) != 0; + _state.EnableVerticalIrq = (value & 0x20) != 0; + _state.EnableHorizontalIrq = (value & 0x10) != 0; + _state.EnableAutoJoypadRead = (value & 0x01) != 0; - case 0x4201: - //TODO WRIO - Programmable I/O port (out-port) - if((_state.IoPortOutput & 0x80) && !(value & 0x80)) { - _ppu->LatchLocationValues(); - } - _state.IoPortOutput = value; - break; + SetNmiFlag(_nmiFlag); + SetIrqFlag(_irqFlag); + break; - case 0x4202: - case 0x4203: - case 0x4204: - case 0x4205: - case 0x4206: - _aluMulDiv.Write(addr, value); - break; + case 0x4201: + //TODO WRIO - Programmable I/O port (out-port) + if ((_state.IoPortOutput & 0x80) && !(value & 0x80)) + { + _ppu->LatchLocationValues(); + } + _state.IoPortOutput = value; + break; - case 0x4207: - _state.HorizontalTimer = (_state.HorizontalTimer & 0x100) | value; - ProcessIrqCounters(); - break; + case 0x4202: + case 0x4203: + case 0x4204: + case 0x4205: + case 0x4206: + _aluMulDiv.Write(addr, value); + break; - case 0x4208: - _state.HorizontalTimer = (_state.HorizontalTimer & 0xFF) | ((value & 0x01) << 8); - ProcessIrqCounters(); - break; + case 0x4207: + _state.HorizontalTimer = (_state.HorizontalTimer & 0x100) | value; + ProcessIrqCounters(); + break; - case 0x4209: - _state.VerticalTimer = (_state.VerticalTimer & 0x100) | value; + case 0x4208: + _state.HorizontalTimer = (_state.HorizontalTimer & 0xFF) | ((value & 0x01) << 8); + ProcessIrqCounters(); + break; - //Calling this here fixes flashing issue in "Shin Nihon Pro Wrestling Kounin - '95 Tokyo Dome Battle 7" - //The write to change from scanline 16 to 17 occurs between both ProcessIrqCounter calls, which causes the IRQ - //line to always be high (since the previous check is on scanline 16, and the next check on scanline 17) - ProcessIrqCounters(); - break; + case 0x4209: + _state.VerticalTimer = (_state.VerticalTimer & 0x100) | value; - case 0x420A: - _state.VerticalTimer = (_state.VerticalTimer & 0xFF) | ((value & 0x01) << 8); - ProcessIrqCounters(); - break; + //Calling this here fixes flashing issue in "Shin Nihon Pro Wrestling Kounin - '95 Tokyo Dome Battle 7" + //The write to change from scanline 16 to 17 occurs between both ProcessIrqCounter calls, which causes the IRQ + //line to always be high (since the previous check is on scanline 16, and the next check on scanline 17) + ProcessIrqCounters(); + break; - case 0x420D: _state.EnableFastRom = (value & 0x01) != 0; break; + case 0x420A: + _state.VerticalTimer = (_state.VerticalTimer & 0xFF) | ((value & 0x01) << 8); + ProcessIrqCounters(); + break; - default: - LogDebug("[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); - break; + case 0x420D: _state.EnableFastRom = (value & 0x01) != 0; + break; + + default: + LogDebug( + "[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); + break; } } @@ -235,11 +252,13 @@ AluState InternalRegisters::GetAluState() return _aluMulDiv.GetState(); } -void InternalRegisters::Serialize(Serializer &s) +void InternalRegisters::Serialize(Serializer& s) { s.Stream( - _state.EnableFastRom, _nmiFlag, _state.EnableNmi, _state.EnableHorizontalIrq, _state.EnableVerticalIrq, _state.HorizontalTimer, - _state.VerticalTimer, _state.IoPortOutput, _state.ControllerData[0], _state.ControllerData[1], _state.ControllerData[2], _state.ControllerData[3], + _state.EnableFastRom, _nmiFlag, _state.EnableNmi, _state.EnableHorizontalIrq, _state.EnableVerticalIrq, + _state.HorizontalTimer, + _state.VerticalTimer, _state.IoPortOutput, _state.ControllerData[0], _state.ControllerData[1], + _state.ControllerData[2], _state.ControllerData[3], _irqLevel, _needIrq, _state.EnableAutoJoypadRead, _irqFlag ); diff --git a/Core/InternalRegisters.h b/Core/InternalRegisters.h index 8831d43..e0aae85 100644 --- a/Core/InternalRegisters.h +++ b/Core/InternalRegisters.h @@ -24,7 +24,7 @@ private: bool _irqLevel = false; uint8_t _needIrq = 0; bool _irqFlag = false; - + void SetIrqFlag(bool irqFlag); public: @@ -46,7 +46,7 @@ public: bool IsFastRomEnabled() { return _state.EnableFastRom; } uint16_t GetHorizontalTimer() { return _state.HorizontalTimer; } uint16_t GetVerticalTimer() { return _state.VerticalTimer; } - + uint8_t Peek(uint16_t addr); uint8_t Read(uint16_t addr); void Write(uint16_t addr, uint8_t value); @@ -54,28 +54,32 @@ public: InternalRegisterState GetState(); AluState GetAluState(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; void InternalRegisters::ProcessIrqCounters() { - if(_needIrq > 0) { + if (_needIrq > 0) + { _needIrq--; - if(_needIrq == 0) { + if (_needIrq == 0) + { SetIrqFlag(true); } } bool irqLevel = ( (_state.EnableHorizontalIrq || _state.EnableVerticalIrq) && - (!_state.EnableHorizontalIrq || (_state.HorizontalTimer <= 339 && (_ppu->GetCycle() == _state.HorizontalTimer) && (_ppu->GetLastScanline() != _ppu->GetRealScanline() || _state.HorizontalTimer < 339))) && + (!_state.EnableHorizontalIrq || (_state.HorizontalTimer <= 339 && (_ppu->GetCycle() == _state.HorizontalTimer) && + (_ppu->GetLastScanline() != _ppu->GetRealScanline() || _state.HorizontalTimer < 339))) && (!_state.EnableVerticalIrq || _ppu->GetRealScanline() == _state.VerticalTimer) ); - if(!_irqLevel && irqLevel) { + if (!_irqLevel && irqLevel) + { //Trigger IRQ signal 16 master clocks later _needIrq = 4; } _irqLevel = irqLevel; _cpu->SetNmiFlag(_state.EnableNmi & _nmiFlag); -} \ No newline at end of file +} diff --git a/Core/KeyManager.cpp b/Core/KeyManager.cpp index 13ea23f..7b8c6f1 100644 --- a/Core/KeyManager.cpp +++ b/Core/KeyManager.cpp @@ -6,7 +6,7 @@ #include "VideoDecoder.h" IKeyManager* KeyManager::_keyManager = nullptr; -MousePosition KeyManager::_mousePosition = { 0, 0 }; +MousePosition KeyManager::_mousePosition = {0, 0}; atomic KeyManager::_xMouseMovement; atomic KeyManager::_yMouseMovement; EmuSettings* KeyManager::_settings = nullptr; @@ -20,19 +20,21 @@ void KeyManager::RegisterKeyManager(IKeyManager* keyManager) void KeyManager::RefreshKeyState() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->RefreshState(); } } -void KeyManager::SetSettings(EmuSettings *settings) +void KeyManager::SetSettings(EmuSettings* settings) { _settings = settings; } bool KeyManager::IsKeyPressed(uint32_t keyCode) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _settings->IsInputEnabled() && _keyManager->IsKeyPressed(keyCode); } return false; @@ -40,7 +42,8 @@ bool KeyManager::IsKeyPressed(uint32_t keyCode) bool KeyManager::IsMouseButtonPressed(MouseButton button) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _settings->IsInputEnabled() && _keyManager->IsMouseButtonPressed(button); } return false; @@ -48,7 +51,8 @@ bool KeyManager::IsMouseButtonPressed(MouseButton button) vector KeyManager::GetPressedKeys() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetPressedKeys(); } return vector(); @@ -56,7 +60,8 @@ vector KeyManager::GetPressedKeys() string KeyManager::GetKeyName(uint32_t keyCode) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetKeyName(keyCode); } return ""; @@ -64,7 +69,8 @@ string KeyManager::GetKeyName(uint32_t keyCode) uint32_t KeyManager::GetKeyCode(string keyName) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetKeyCode(keyName); } return 0; @@ -72,7 +78,8 @@ uint32_t KeyManager::GetKeyCode(string keyName) void KeyManager::UpdateDevices() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { _keyManager->UpdateDevices(); } } @@ -97,18 +104,21 @@ MouseMovement KeyManager::GetMouseMovement(double videoScale, double mouseSensit void KeyManager::SetMousePosition(shared_ptr console, double x, double y) { - if(x < 0 || y < 0) { + if (x < 0 || y < 0) + { _mousePosition.X = -1; _mousePosition.Y = -1; - } else { + } + else + { OverscanDimensions overscan = console->GetSettings()->GetOverscan(); ScreenSize size = console->GetVideoDecoder()->GetScreenSize(true); - _mousePosition.X = (int32_t)(x*size.Width + overscan.Left); - _mousePosition.Y = (int32_t)(y*size.Height + overscan.Top); + _mousePosition.X = (int32_t)(x * size.Width + overscan.Left); + _mousePosition.Y = (int32_t)(y * size.Height + overscan.Top); } } MousePosition KeyManager::GetMousePosition() { return _mousePosition; -} \ No newline at end of file +} diff --git a/Core/KeyManager.h b/Core/KeyManager.h index 8a6450f..eb6ca12 100644 --- a/Core/KeyManager.h +++ b/Core/KeyManager.h @@ -26,10 +26,10 @@ public: static uint32_t GetKeyCode(string keyName); static void UpdateDevices(); - + static void SetMouseMovement(int16_t x, int16_t y); static MouseMovement GetMouseMovement(double videoScale, double mouseSensitivity); - + static void SetMousePosition(shared_ptr console, double x, double y); static MousePosition GetMousePosition(); -}; \ No newline at end of file +}; diff --git a/Core/LabelManager.cpp b/Core/LabelManager.cpp index 3f10cbb..bdce85a 100644 --- a/Core/LabelManager.cpp +++ b/Core/LabelManager.cpp @@ -4,7 +4,7 @@ #include "DebugUtilities.h" #include "DebugBreakHelper.h" -LabelManager::LabelManager(Debugger *debugger) +LabelManager::LabelManager(Debugger* debugger) { _debugger = debugger; } @@ -22,13 +22,16 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab uint64_t key = GetLabelKey(address, memType); auto existingLabel = _codeLabels.find(key); - if(existingLabel != _codeLabels.end()) { + if (existingLabel != _codeLabels.end()) + { _codeLabelReverseLookup.erase(existingLabel->second.Label); } _codeLabels.erase(key); - if(!label.empty() || !comment.empty()) { - if(label.size() > 400) { + if (!label.empty() || !comment.empty()) + { + if (label.size() > 400) + { //Restrict labels to 400 bytes label = label.substr(0, 400); } @@ -44,48 +47,67 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32); - case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32); - case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32); - case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32); - case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32); - case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32); - case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32); - case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32); - case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32); - case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32); - case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32); - case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32); - case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32); - case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32); - case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32); - case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32); - case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32); - default: return -1; + switch (memType) + { + case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32); + case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32); + case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32); + case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32); + case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32); + case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32); + case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32); + case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32); + case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32); + case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32); + case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32); + case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32); + case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32); + case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32); + case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32); + case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32); + case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32); + default: return -1; } } SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) { - switch(key & ~(uint64_t)0xFFFFFFFF) { - case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; break; - case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; break; - case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; break; - case ((uint64_t)4 << 32): return SnesMemoryType::Register; break; - case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; break; - case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break; - case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break; - case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break; - case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; break; - case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; break; - case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; break; - case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; break; - case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; break; - case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; break; - case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; break; - case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; break; - case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; break; + switch (key & ~(uint64_t)0xFFFFFFFF) + { + case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; + break; + case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; + break; + case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; + break; + case ((uint64_t)4 << 32): return SnesMemoryType::Register; + break; + case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; + break; + case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; + break; + case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; + break; + case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; + break; + case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; + break; + case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; + break; + case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; + break; + case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; + break; + case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; + break; + case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; + break; + case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; + break; + case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; + break; + case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; + break; } throw std::runtime_error("Invalid label key"); @@ -93,30 +115,36 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) string LabelManager::GetLabel(AddressInfo address) { - string label ; - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { - if(address.Type == SnesMemoryType::GameboyMemory) { + string label; + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { + if (address.Type == SnesMemoryType::GameboyMemory) + { //Labels for GB registers - if(InternalGetLabel(address, label)) { + if (InternalGetLabel(address, label)) + { return label; } } address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { InternalGetLabel(address, label); } return label; } -bool LabelManager::InternalGetLabel(AddressInfo address, string &label) +bool LabelManager::InternalGetLabel(AddressInfo address, string& label) { int64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { label = result->second.Label; return true; } @@ -128,9 +156,11 @@ string LabelManager::GetComment(AddressInfo absAddress) { uint64_t key = GetLabelKey(absAddress.Address, absAddress.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { return result->second.Comment; } } @@ -138,18 +168,22 @@ string LabelManager::GetComment(AddressInfo absAddress) return ""; } -bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo &labelInfo) +bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo& labelInfo) { - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { int64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { labelInfo = result->second; return true; } @@ -158,19 +192,21 @@ bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo &labelInfo) return false; } -bool LabelManager::ContainsLabel(string &label) +bool LabelManager::ContainsLabel(string& label) { return _codeLabelReverseLookup.find(label) != _codeLabelReverseLookup.end(); } -int32_t LabelManager::GetLabelRelativeAddress(string &label, CpuType cpuType) +int32_t LabelManager::GetLabelRelativeAddress(string& label, CpuType cpuType) { auto result = _codeLabelReverseLookup.find(label); - if(result != _codeLabelReverseLookup.end()) { + if (result != _codeLabelReverseLookup.end()) + { uint64_t key = result->second; SnesMemoryType type = GetKeyMemoryType(key); - AddressInfo addr { (int32_t)(key & 0xFFFFFFFF), type }; - if(type <= DebugUtilities::GetLastCpuMemoryType()) { + AddressInfo addr{(int32_t)(key & 0xFFFFFFFF), type}; + if (type <= DebugUtilities::GetLastCpuMemoryType()) + { return addr.Address; } return _debugger->GetRelativeAddress(addr, cpuType).Address; @@ -181,13 +217,16 @@ int32_t LabelManager::GetLabelRelativeAddress(string &label, CpuType cpuType) bool LabelManager::HasLabelOrComment(AddressInfo address) { - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { uint64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { return _codeLabels.find(key) != _codeLabels.end(); } } diff --git a/Core/LabelManager.h b/Core/LabelManager.h index cf7a3df..a55dd3d 100644 --- a/Core/LabelManager.h +++ b/Core/LabelManager.h @@ -28,25 +28,25 @@ private: unordered_map _codeLabels; unordered_map _codeLabelReverseLookup; - Debugger *_debugger; + Debugger* _debugger; int64_t GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType); SnesMemoryType GetKeyMemoryType(uint64_t key); bool InternalGetLabel(AddressInfo address, string& label); public: - LabelManager(Debugger *debugger); + LabelManager(Debugger* debugger); void SetLabel(uint32_t address, SnesMemoryType memType, string label, string comment); void ClearLabels(); - int32_t GetLabelRelativeAddress(string &label, CpuType cpuType = CpuType::Cpu); + int32_t GetLabelRelativeAddress(string& label, CpuType cpuType = CpuType::Cpu); string GetLabel(AddressInfo address); string GetComment(AddressInfo absAddress); - bool GetLabelAndComment(AddressInfo address, LabelInfo &label); + bool GetLabelAndComment(AddressInfo address, LabelInfo& label); - bool ContainsLabel(string &label); + bool ContainsLabel(string& label); bool HasLabelOrComment(AddressInfo address); }; diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index 725a40c..1e3def8 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -57,45 +57,45 @@ void LuaApi::SetContext(ScriptingContext* context) _ppu = _console->GetPpu().get(); } -int LuaApi::GetLibrary(lua_State *lua) +int LuaApi::GetLibrary(lua_State* lua) { static const luaL_Reg apilib[] = { - { "read", LuaApi::ReadMemory }, - { "write", LuaApi::WriteMemory }, - { "readWord", LuaApi::ReadMemoryWord }, - { "writeWord", LuaApi::WriteMemoryWord }, - { "getPrgRomOffset", LuaApi::GetPrgRomOffset }, - { "addMemoryCallback", LuaApi::RegisterMemoryCallback }, - { "removeMemoryCallback", LuaApi::UnregisterMemoryCallback }, - { "addEventCallback", LuaApi::RegisterEventCallback }, - { "removeEventCallback", LuaApi::UnregisterEventCallback }, - { "drawString", LuaApi::DrawString }, - { "drawPixel", LuaApi::DrawPixel }, - { "drawLine", LuaApi::DrawLine }, - { "drawRectangle", LuaApi::DrawRectangle }, - { "clearScreen", LuaApi::ClearScreen }, - { "getScreenBuffer", LuaApi::GetScreenBuffer }, - { "setScreenBuffer", LuaApi::SetScreenBuffer }, - { "getPixel", LuaApi::GetPixel }, - { "getMouseState", LuaApi::GetMouseState }, - { "log", LuaApi::Log }, - { "displayMessage", LuaApi::DisplayMessage }, - { "reset", LuaApi::Reset }, - { "breakExecution", LuaApi::Break }, - { "resume", LuaApi::Resume }, - { "execute", LuaApi::Execute }, - { "rewind", LuaApi::Rewind }, - { "takeScreenshot", LuaApi::TakeScreenshot }, - { "isKeyPressed", LuaApi::IsKeyPressed }, - { "getInput", LuaApi::GetInput }, - { "getAccessCounters", LuaApi::GetAccessCounters }, - { "resetAccessCounters", LuaApi::ResetAccessCounters }, - { "getState", LuaApi::GetState }, - { "getScriptDataFolder", LuaApi::GetScriptDataFolder }, - { "getRomInfo", LuaApi::GetRomInfo }, - { "getLogWindowLog", LuaApi::GetLogWindowLog }, - { "getLabelAddress", LuaApi::GetLabelAddress }, - { NULL,NULL } + {"read", LuaApi::ReadMemory}, + {"write", LuaApi::WriteMemory}, + {"readWord", LuaApi::ReadMemoryWord}, + {"writeWord", LuaApi::WriteMemoryWord}, + {"getPrgRomOffset", LuaApi::GetPrgRomOffset}, + {"addMemoryCallback", LuaApi::RegisterMemoryCallback}, + {"removeMemoryCallback", LuaApi::UnregisterMemoryCallback}, + {"addEventCallback", LuaApi::RegisterEventCallback}, + {"removeEventCallback", LuaApi::UnregisterEventCallback}, + {"drawString", LuaApi::DrawString}, + {"drawPixel", LuaApi::DrawPixel}, + {"drawLine", LuaApi::DrawLine}, + {"drawRectangle", LuaApi::DrawRectangle}, + {"clearScreen", LuaApi::ClearScreen}, + {"getScreenBuffer", LuaApi::GetScreenBuffer}, + {"setScreenBuffer", LuaApi::SetScreenBuffer}, + {"getPixel", LuaApi::GetPixel}, + {"getMouseState", LuaApi::GetMouseState}, + {"log", LuaApi::Log}, + {"displayMessage", LuaApi::DisplayMessage}, + {"reset", LuaApi::Reset}, + {"breakExecution", LuaApi::Break}, + {"resume", LuaApi::Resume}, + {"execute", LuaApi::Execute}, + {"rewind", LuaApi::Rewind}, + {"takeScreenshot", LuaApi::TakeScreenshot}, + {"isKeyPressed", LuaApi::IsKeyPressed}, + {"getInput", LuaApi::GetInput}, + {"getAccessCounters", LuaApi::GetAccessCounters}, + {"resetAccessCounters", LuaApi::ResetAccessCounters}, + {"getState", LuaApi::GetState}, + {"getScriptDataFolder", LuaApi::GetScriptDataFolder}, + {"getRomInfo", LuaApi::GetRomInfo}, + {"getLogWindowLog", LuaApi::GetLogWindowLog}, + {"getLabelAddress", LuaApi::GetLabelAddress}, + {NULL,NULL} }; luaL_newlib(lua, apilib); @@ -205,7 +205,7 @@ int LuaApi::GetLibrary(lua_State *lua) return 1; } -int LuaApi::GetLabelAddress(lua_State *lua) +int LuaApi::GetLabelAddress(lua_State* lua) { LuaCallHelper l(lua); string label = l.ReadString(); @@ -214,7 +214,8 @@ int LuaApi::GetLabelAddress(lua_State *lua) std::shared_ptr lblMan = _debugger->GetLabelManager(); int32_t value = lblMan->GetLabelRelativeAddress(label); - if(value == -2) { + if (value == -2) + { //Check to see if the label is a multi-byte label instead string mbLabel = label + "+0"; value = lblMan->GetLabelRelativeAddress(mbLabel); @@ -226,7 +227,7 @@ int LuaApi::GetLabelAddress(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ReadMemory(lua_State *lua) +int LuaApi::ReadMemory(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(3); @@ -242,7 +243,7 @@ int LuaApi::ReadMemory(lua_State *lua) return l.ReturnCount(); } -int LuaApi::WriteMemory(lua_State *lua) +int LuaApi::WriteMemory(lua_State* lua) { LuaCallHelper l(lua); int type = l.ReadInteger(); @@ -257,7 +258,7 @@ int LuaApi::WriteMemory(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ReadMemoryWord(lua_State *lua) +int LuaApi::ReadMemoryWord(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(3); @@ -273,7 +274,7 @@ int LuaApi::ReadMemoryWord(lua_State *lua) return l.ReturnCount(); } -int LuaApi::WriteMemoryWord(lua_State *lua) +int LuaApi::WriteMemoryWord(lua_State* lua) { LuaCallHelper l(lua); int type = l.ReadInteger(); @@ -288,20 +289,20 @@ int LuaApi::WriteMemoryWord(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetPrgRomOffset(lua_State *lua) +int LuaApi::GetPrgRomOffset(lua_State* lua) { LuaCallHelper l(lua); int address = l.ReadInteger(); checkminparams(1); errorCond(address < 0 || address > 0xFFFF, "address must be between 0 and $FFFF"); - - AddressInfo relAddress { address, SnesMemoryType::CpuMemory }; + + AddressInfo relAddress{address, SnesMemoryType::CpuMemory}; int32_t prgRomOffset = _debugger->GetAbsoluteAddress(relAddress).Address; l.Return(prgRomOffset); return l.ReturnCount(); } -int LuaApi::RegisterMemoryCallback(lua_State *lua) +int LuaApi::RegisterMemoryCallback(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -312,21 +313,25 @@ int LuaApi::RegisterMemoryCallback(lua_State *lua) int reference = l.GetReference(); checkminparams(3); - if(endAddr == -1) { + if (endAddr == -1) + { endAddr = startAddr; } errorCond(startAddr > endAddr, "start address must be <= end address"); - errorCond(callbackType < CallbackType::CpuRead || callbackType > CallbackType::CpuExec, "the specified type is invalid"); + errorCond(callbackType < CallbackType::CpuRead || callbackType > CallbackType::CpuExec, + "the specified type is invalid"); errorCond(cpuType < CpuType::Cpu || cpuType > CpuType::Gameboy, "the cpu type is invalid"); errorCond(reference == LUA_NOREF, "the specified function could not be found"); _context->RegisterMemoryCallback(callbackType, startAddr, endAddr, cpuType, reference); - _context->Log("Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex((uint32_t)endAddr)); + _context->Log( + "Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex( + (uint32_t)endAddr)); l.Return(reference); return l.ReturnCount(); } -int LuaApi::UnregisterMemoryCallback(lua_State *lua) +int LuaApi::UnregisterMemoryCallback(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -339,7 +344,8 @@ int LuaApi::UnregisterMemoryCallback(lua_State *lua) checkminparams(3); - if(endAddr == -1) { + if (endAddr == -1) + { endAddr = startAddr; } @@ -350,7 +356,7 @@ int LuaApi::UnregisterMemoryCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::RegisterEventCallback(lua_State *lua) +int LuaApi::RegisterEventCallback(lua_State* lua) { LuaCallHelper l(lua); EventType type = (EventType)l.ReadInteger(); @@ -363,7 +369,7 @@ int LuaApi::RegisterEventCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::UnregisterEventCallback(lua_State *lua) +int LuaApi::UnregisterEventCallback(lua_State* lua) { LuaCallHelper l(lua); EventType type = (EventType)l.ReadInteger(); @@ -375,7 +381,7 @@ int LuaApi::UnregisterEventCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawString(lua_State *lua) +int LuaApi::DrawString(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(7); @@ -394,7 +400,7 @@ int LuaApi::DrawString(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawLine(lua_State *lua) +int LuaApi::DrawLine(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(7); @@ -413,7 +419,7 @@ int LuaApi::DrawLine(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawPixel(lua_State *lua) +int LuaApi::DrawPixel(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -430,7 +436,7 @@ int LuaApi::DrawPixel(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawRectangle(lua_State *lua) +int LuaApi::DrawRectangle(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(8); @@ -450,7 +456,7 @@ int LuaApi::DrawRectangle(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ClearScreen(lua_State *lua) +int LuaApi::ClearScreen(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -459,16 +465,20 @@ int LuaApi::ClearScreen(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetScreenBuffer(lua_State *lua) +int LuaApi::GetScreenBuffer(lua_State* lua) { LuaCallHelper l(lua); int multiplier = _ppu->IsHighResOutput() ? 2 : 1; lua_newtable(lua); - for(int y = 0; y < 239; y++) { - for(int x = 0; x < 256; x++) { - lua_pushinteger(lua, DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); + for (int y = 0; y < 239; y++) + { + for (int x = 0; x < 256; x++) + { + lua_pushinteger( + lua, DefaultVideoFilter::ToArgb( + *(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); lua_rawseti(lua, -2, (y << 8) + x); } } @@ -476,23 +486,24 @@ int LuaApi::GetScreenBuffer(lua_State *lua) return 1; } -int LuaApi::SetScreenBuffer(lua_State *lua) +int LuaApi::SetScreenBuffer(lua_State* lua) { LuaCallHelper l(lua); - uint32_t pixels[256*239] = {}; + uint32_t pixels[256 * 239] = {}; luaL_checktype(lua, 1, LUA_TTABLE); - for(int i = 0; i < 256*239; i++) { + for (int i = 0; i < 256 * 239; i++) + { lua_rawgeti(lua, 1, i); pixels[i] = l.ReadInteger() ^ 0xFF000000; } - + int startFrame = _console->GetFrameCount(); _console->GetDebugHud()->DrawScreenBuffer(pixels, startFrame); return l.ReturnCount(); } -int LuaApi::GetPixel(lua_State *lua) +int LuaApi::GetPixel(lua_State* lua) { LuaCallHelper l(lua); int y = l.ReadInteger(); @@ -503,11 +514,13 @@ int LuaApi::GetPixel(lua_State *lua) int multiplier = _ppu->IsHighResOutput() ? 2 : 1; //Ignores intensify & grayscale bits - l.Return(DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); + l.Return( + DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & + 0xFFFFFF); return l.ReturnCount(); } -int LuaApi::GetMouseState(lua_State *lua) +int LuaApi::GetMouseState(lua_State* lua) { LuaCallHelper l(lua); MousePosition pos = KeyManager::GetMousePosition(); @@ -521,7 +534,7 @@ int LuaApi::GetMouseState(lua_State *lua) return 1; } -int LuaApi::Log(lua_State *lua) +int LuaApi::Log(lua_State* lua) { LuaCallHelper l(lua); string text = l.ReadString(); @@ -530,7 +543,7 @@ int LuaApi::Log(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DisplayMessage(lua_State *lua) +int LuaApi::DisplayMessage(lua_State* lua) { LuaCallHelper l(lua); string text = l.ReadString(); @@ -540,7 +553,7 @@ int LuaApi::DisplayMessage(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Reset(lua_State *lua) +int LuaApi::Reset(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -549,7 +562,7 @@ int LuaApi::Reset(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Break(lua_State *lua) +int LuaApi::Break(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -558,7 +571,7 @@ int LuaApi::Break(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Resume(lua_State *lua) +int LuaApi::Resume(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -567,7 +580,7 @@ int LuaApi::Resume(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Execute(lua_State *lua) +int LuaApi::Execute(lua_State* lua) { LuaCallHelper l(lua); StepType type = (StepType)l.ReadInteger(); @@ -582,7 +595,7 @@ int LuaApi::Execute(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Rewind(lua_State *lua) +int LuaApi::Rewind(lua_State* lua) { LuaCallHelper l(lua); int seconds = l.ReadInteger(); @@ -593,7 +606,7 @@ int LuaApi::Rewind(lua_State *lua) return l.ReturnCount(); } -int LuaApi::TakeScreenshot(lua_State *lua) +int LuaApi::TakeScreenshot(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -603,7 +616,7 @@ int LuaApi::TakeScreenshot(lua_State *lua) return l.ReturnCount(); } -int LuaApi::IsKeyPressed(lua_State *lua) +int LuaApi::IsKeyPressed(lua_State* lua) { LuaCallHelper l(lua); string keyName = l.ReadString(); @@ -614,14 +627,15 @@ int LuaApi::IsKeyPressed(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetInput(lua_State *lua) +int LuaApi::GetInput(lua_State* lua) { LuaCallHelper l(lua); int port = l.ReadInteger(); checkparams(); errorCond(port < 0 || port > 4, "Invalid port number - must be between 0 to 4"); - shared_ptr controller = std::dynamic_pointer_cast(_console->GetControlManager()->GetControlDevice(port)); + shared_ptr controller = std::dynamic_pointer_cast( + _console->GetControlManager()->GetControlDevice(port)); errorCond(controller == nullptr, "Input port must be connected to a standard controller"); lua_newtable(lua); @@ -640,7 +654,7 @@ int LuaApi::GetInput(lua_State *lua) return 1; } -int LuaApi::GetAccessCounters(lua_State *lua) +int LuaApi::GetAccessCounters(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(2); @@ -656,33 +670,37 @@ int LuaApi::GetAccessCounters(lua_State *lua) _debugger->GetMemoryAccessCounter()->GetAccessCounts(0, size, memoryType, counts.data()); lua_newtable(lua); - switch(operationType) { - default: - case MemoryOperationType::Read: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].ReadCount); - lua_rawseti(lua, -2, i); - } - break; + switch (operationType) + { + default: + case MemoryOperationType::Read: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].ReadCount); + lua_rawseti(lua, -2, i); + } + break; - case MemoryOperationType::Write: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].WriteCount); - lua_rawseti(lua, -2, i); - } - break; + case MemoryOperationType::Write: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].WriteCount); + lua_rawseti(lua, -2, i); + } + break; - case MemoryOperationType::ExecOpCode: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].ExecCount); - lua_rawseti(lua, -2, i); - } - break; + case MemoryOperationType::ExecOpCode: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].ExecCount); + lua_rawseti(lua, -2, i); + } + break; } return 1; } -int LuaApi::ResetAccessCounters(lua_State *lua) +int LuaApi::ResetAccessCounters(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -690,19 +708,20 @@ int LuaApi::ResetAccessCounters(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetScriptDataFolder(lua_State *lua) +int LuaApi::GetScriptDataFolder(lua_State* lua) { LuaCallHelper l(lua); checkparams(); string baseFolder = FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "LuaScriptData"); FolderUtilities::CreateFolder(baseFolder); - string scriptFolder = FolderUtilities::CombinePath(baseFolder, FolderUtilities::GetFilename(_context->GetScriptName(), false)); + string scriptFolder = FolderUtilities::CombinePath( + baseFolder, FolderUtilities::GetFilename(_context->GetScriptName(), false)); FolderUtilities::CreateFolder(scriptFolder); l.Return(scriptFolder); return l.ReturnCount(); } -int LuaApi::GetRomInfo(lua_State *lua) +int LuaApi::GetRomInfo(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -717,16 +736,16 @@ int LuaApi::GetRomInfo(lua_State *lua) return 1; } -int LuaApi::GetLogWindowLog(lua_State *lua) +int LuaApi::GetLogWindowLog(lua_State* lua) { LuaCallHelper l(lua); checkparams(); - + l.Return(MessageManager::GetLog()); return l.ReturnCount(); } -int LuaApi::GetState(lua_State *lua) +int LuaApi::GetState(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -759,9 +778,9 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(hClock, state.Ppu.HClock); lua_pushboolvalue(forcedVblank, state.Ppu.ForcedVblank); lua_pushintvalue(screenBrightness, state.Ppu.ScreenBrightness); - + lua_starttable("mode7"); - + lua_starttable("matrix"); lua_pusharrayvalue(0, state.Ppu.Mode7.Matrix[0]); lua_pusharrayvalue(1, state.Ppu.Mode7.Matrix[0]); @@ -784,11 +803,12 @@ int LuaApi::GetState(lua_State *lua) lua_pushboolvalue(mode1Bg3Priority, state.Ppu.Mode1Bg3Priority); lua_pushintvalue(mainScreenLayers, state.Ppu.MainScreenLayers); lua_pushintvalue(subScreenLayers, state.Ppu.SubScreenLayers); - + lua_starttable("layers") - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { lua_pushinteger(lua, i); - + lua_newtable(lua); lua_pushintvalue(tilemapAddress, state.Ppu.Layers[i].TilemapAddress); lua_pushintvalue(chrAddress, state.Ppu.Layers[i].ChrAddress); @@ -796,34 +816,35 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(vScroll, state.Ppu.Layers[i].VScroll); lua_pushintvalue(doubleWidth, state.Ppu.Layers[i].DoubleWidth); lua_pushintvalue(doubleHeight, state.Ppu.Layers[i].DoubleHeight); - lua_pushintvalue(largeTiles, state.Ppu.Layers[i].LargeTiles); + lua_pushintvalue(largeTiles, state.Ppu.Layers[i].LargeTiles); lua_settable(lua, -3); } lua_endtable(); //end layers lua_starttable("windows") - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { lua_pushinteger(lua, i); lua_newtable(lua); lua_pushintvalue(activeLayers, ( - (uint8_t)state.Ppu.Window[i].ActiveLayers[0] | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[1] << 1) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[2] << 2) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[3] << 3) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[4] << 4) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[5] << 5) - )); + (uint8_t)state.Ppu.Window[i].ActiveLayers[0] | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[1] << 1) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[2] << 2) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[3] << 3) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[4] << 4) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[5] << 5) + )); lua_pushintvalue(invertedLayers, ( - (uint8_t)state.Ppu.Window[i].InvertedLayers[0] | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[1] << 1) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[2] << 2) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[3] << 3) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[4] << 4) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[5] << 5) - )); + (uint8_t)state.Ppu.Window[i].InvertedLayers[0] | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[1] << 1) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[2] << 2) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[3] << 3) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[4] << 4) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[5] << 5) + )); lua_pushintvalue(left, state.Ppu.Window[i].Left); lua_pushintvalue(right, state.Ppu.Window[i].Right); @@ -831,7 +852,7 @@ int LuaApi::GetState(lua_State *lua) lua_settable(lua, -3); } lua_endtable(); //end windows - + lua_pushboolvalue(windowMaskLogicBg0, (int)state.Ppu.MaskLogic[0]); lua_pushboolvalue(windowMaskLogicBg1, (int)state.Ppu.MaskLogic[1]); lua_pushboolvalue(windowMaskLogicBg2, (int)state.Ppu.MaskLogic[2]); @@ -859,7 +880,7 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(ppu1OpenBus, state.Ppu.Ppu1OpenBus); lua_pushintvalue(ppu2OpenBus, state.Ppu.Ppu2OpenBus); - + lua_pushintvalue(cgramAddress, state.Ppu.CgramAddress); lua_pushintvalue(cgramWriteBuffer, state.Ppu.CgramWriteBuffer); lua_pushboolvalue(cgramAddressLatch, state.Ppu.CgramAddressLatch); @@ -898,7 +919,7 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(x, state.Spc.X); lua_pushintvalue(y, state.Spc.Y); lua_endtable(); //end spc - + return 1; } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaApi.h b/Core/LuaApi.h index 329b4d7..bb8f130 100644 --- a/Core/LuaApi.h +++ b/Core/LuaApi.h @@ -11,44 +11,44 @@ class MemoryDumper; class LuaApi { public: - static void SetContext(ScriptingContext *context); - static int GetLibrary(lua_State *lua); + static void SetContext(ScriptingContext* context); + static int GetLibrary(lua_State* lua); - static int GetLabelAddress(lua_State *lua); + static int GetLabelAddress(lua_State* lua); - static int ReadMemory(lua_State *lua); - static int WriteMemory(lua_State *lua); - static int ReadMemoryWord(lua_State *lua); - static int WriteMemoryWord(lua_State *lua); - static int GetPrgRomOffset(lua_State *lua); + static int ReadMemory(lua_State* lua); + static int WriteMemory(lua_State* lua); + static int ReadMemoryWord(lua_State* lua); + static int WriteMemoryWord(lua_State* lua); + static int GetPrgRomOffset(lua_State* lua); //static int RevertPrgChrChanges(lua_State *lua); - static int RegisterMemoryCallback(lua_State *lua); - static int UnregisterMemoryCallback(lua_State *lua); - static int RegisterEventCallback(lua_State *lua); - static int UnregisterEventCallback(lua_State *lua); - - static int DrawString(lua_State *lua); - static int DrawLine(lua_State *lua); - static int DrawPixel(lua_State *lua); - static int DrawRectangle(lua_State *lua); - static int ClearScreen(lua_State *lua); - static int GetScreenBuffer(lua_State *lua); - static int SetScreenBuffer(lua_State *lua); - static int GetPixel(lua_State *lua); - static int GetMouseState(lua_State *lua); + static int RegisterMemoryCallback(lua_State* lua); + static int UnregisterMemoryCallback(lua_State* lua); + static int RegisterEventCallback(lua_State* lua); + static int UnregisterEventCallback(lua_State* lua); - static int Log(lua_State *lua); - static int DisplayMessage(lua_State *lua); - - static int Reset(lua_State *lua); - static int Stop(lua_State *lua); - static int Break(lua_State *lua); - static int Resume(lua_State *lua); - static int Execute(lua_State *lua); - static int Rewind(lua_State *lua); + static int DrawString(lua_State* lua); + static int DrawLine(lua_State* lua); + static int DrawPixel(lua_State* lua); + static int DrawRectangle(lua_State* lua); + static int ClearScreen(lua_State* lua); + static int GetScreenBuffer(lua_State* lua); + static int SetScreenBuffer(lua_State* lua); + static int GetPixel(lua_State* lua); + static int GetMouseState(lua_State* lua); - static int TakeScreenshot(lua_State *lua); + static int Log(lua_State* lua); + static int DisplayMessage(lua_State* lua); + + static int Reset(lua_State* lua); + static int Stop(lua_State* lua); + static int Break(lua_State* lua); + static int Resume(lua_State* lua); + static int Execute(lua_State* lua); + static int Rewind(lua_State* lua); + + static int TakeScreenshot(lua_State* lua); /*static int SaveSavestate(lua_State *lua); static int LoadSavestate(lua_State *lua); @@ -57,23 +57,23 @@ public: static int GetSavestateData(lua_State *lua); static int ClearSavestateData(lua_State *lua);*/ - static int IsKeyPressed(lua_State *lua); + static int IsKeyPressed(lua_State* lua); - static int GetInput(lua_State *lua); + static int GetInput(lua_State* lua); //static int SetInput(lua_State *lua); /*static int AddCheat(lua_State *lua); static int ClearCheats(lua_State *lua);*/ - static int GetScriptDataFolder(lua_State *lua); - static int GetRomInfo(lua_State *lua); - static int GetLogWindowLog(lua_State *lua); + static int GetScriptDataFolder(lua_State* lua); + static int GetRomInfo(lua_State* lua); + static int GetLogWindowLog(lua_State* lua); //static int SetState(lua_State *lua); - static int GetState(lua_State *lua); + static int GetState(lua_State* lua); - static int GetAccessCounters(lua_State *lua); - static int ResetAccessCounters(lua_State *lua); + static int GetAccessCounters(lua_State* lua); + static int ResetAccessCounters(lua_State* lua); private: static Console* _console; diff --git a/Core/LuaCallHelper.cpp b/Core/LuaCallHelper.cpp index b0dc9b3..971d2ef 100644 --- a/Core/LuaCallHelper.cpp +++ b/Core/LuaCallHelper.cpp @@ -2,25 +2,29 @@ #ifndef LIBRETRO #include "LuaCallHelper.h" -LuaCallHelper::LuaCallHelper(lua_State *lua) : _lua(lua) +LuaCallHelper::LuaCallHelper(lua_State* lua) : _lua(lua) { _stackSize = lua_gettop(lua); } void LuaCallHelper::ForceParamCount(int paramCount) { - while(lua_gettop(_lua) < paramCount) { + while (lua_gettop(_lua) < paramCount) + { lua_pushnil(_lua); } } bool LuaCallHelper::CheckParamCount(int minParamCount) { - if(minParamCount >= 0 && _stackSize < _paramCount && _stackSize >= minParamCount) { + if (minParamCount >= 0 && _stackSize < _paramCount && _stackSize >= minParamCount) + { return true; } - if(_stackSize != _paramCount) { - string message = string("too ") + (_stackSize < _paramCount ? "few" : "many") + " parameters. expected " + std::to_string(_paramCount) + " got " + std::to_string(_stackSize); + if (_stackSize != _paramCount) + { + string message = string("too ") + (_stackSize < _paramCount ? "few" : "many") + " parameters. expected " + + std::to_string(_paramCount) + " got " + std::to_string(_stackSize); luaL_error(_lua, message.c_str()); return false; } @@ -31,7 +35,8 @@ double LuaCallHelper::ReadDouble() { _paramCount++; double value = 0; - if(lua_isnumber(_lua, -1)) { + if (lua_isnumber(_lua, -1)) + { value = lua_tonumber(_lua, -1); } lua_pop(_lua, 1); @@ -42,9 +47,12 @@ bool LuaCallHelper::ReadBool(bool defaultValue) { _paramCount++; bool value = defaultValue; - if(lua_isboolean(_lua, -1)) { + if (lua_isboolean(_lua, -1)) + { value = lua_toboolean(_lua, -1) != 0; - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { value = lua_tonumber(_lua, -1) != 0; } lua_pop(_lua, 1); @@ -55,10 +63,13 @@ Nullable LuaCallHelper::ReadOptionalBool() { _paramCount++; Nullable result; - if(lua_isboolean(_lua, -1)) { + if (lua_isboolean(_lua, -1)) + { result.HasValue = true; result.Value = lua_toboolean(_lua, -1) != 0; - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { result.HasValue = true; result.Value = lua_tonumber(_lua, -1) != 0; } @@ -70,10 +81,13 @@ Nullable LuaCallHelper::ReadOptionalInteger() { _paramCount++; Nullable result; - if(lua_isinteger(_lua, -1)) { + if (lua_isinteger(_lua, -1)) + { result.HasValue = true; result.Value = (uint32_t)lua_tointeger(_lua, -1); - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { result.HasValue = true; result.Value = (uint32_t)lua_tonumber(_lua, -1); } @@ -85,9 +99,12 @@ uint32_t LuaCallHelper::ReadInteger(uint32_t defaultValue) { _paramCount++; uint32_t value = defaultValue; - if(lua_isinteger(_lua, -1)) { + if (lua_isinteger(_lua, -1)) + { value = (uint32_t)lua_tointeger(_lua, -1); - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { value = (uint32_t)lua_tonumber(_lua, -1); } lua_pop(_lua, 1); @@ -99,7 +116,8 @@ string LuaCallHelper::ReadString() _paramCount++; size_t len; string str; - if(lua_isstring(_lua, -1)) { + if (lua_isstring(_lua, -1)) + { const char* cstr = lua_tolstring(_lua, -1, &len); str = string(cstr, len); } @@ -110,9 +128,12 @@ string LuaCallHelper::ReadString() int LuaCallHelper::GetReference() { _paramCount++; - if(lua_isfunction(_lua, -1)) { + if (lua_isfunction(_lua, -1)) + { return luaL_ref(_lua, LUA_REGISTRYINDEX); - } else { + } + else + { lua_pop(_lua, 1); return LUA_NOREF; } @@ -147,4 +168,4 @@ int LuaCallHelper::ReturnCount() return _returnCount; } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaCallHelper.h b/Core/LuaCallHelper.h index e4fc768..9711d6b 100644 --- a/Core/LuaCallHelper.h +++ b/Core/LuaCallHelper.h @@ -2,7 +2,7 @@ #include "stdafx.h" #include "../Lua/lua.hpp" -template +template struct Nullable { bool HasValue = false; @@ -38,4 +38,4 @@ public: void Return(string value); int ReturnCount(); -}; \ No newline at end of file +}; diff --git a/Core/LuaScriptingContext.cpp b/Core/LuaScriptingContext.cpp index e7cbae9..19cf63d 100644 --- a/Core/LuaScriptingContext.cpp +++ b/Core/LuaScriptingContext.cpp @@ -19,22 +19,28 @@ LuaScriptingContext::LuaScriptingContext(Debugger* debugger) : ScriptingContext( LuaScriptingContext::~LuaScriptingContext() { - if(_lua) { + if (_lua) + { //Cleanup all references, this is required to prevent crashes that can occur when calling lua_close std::unordered_set references; - for(int i = (int)CallbackType::CpuRead; i <= (int)CallbackType::CpuExec; i++) { - for(MemoryCallback &callback : _callbacks[i]) { + for (int i = (int)CallbackType::CpuRead; i <= (int)CallbackType::CpuExec; i++) + { + for (MemoryCallback& callback : _callbacks[i]) + { references.emplace(callback.Reference); } } - for(int i = (int)EventType::Reset; i < (int)EventType::EventTypeSize; i++) { - for(int &ref : _eventCallbacks[i]) { + for (int i = (int)EventType::Reset; i < (int)EventType::EventTypeSize; i++) + { + for (int& ref : _eventCallbacks[i]) + { references.emplace(ref); } } - for(const int &ref : references) { + for (const int& ref : references) + { luaL_unref(_lua, LUA_REGISTRYINDEX, ref); } @@ -48,9 +54,10 @@ void LuaScriptingContext::SetScriptTimeout(uint32_t timeout) _timeout = timeout; } -void LuaScriptingContext::ExecutionCountHook(lua_State *lua, lua_Debug *ar) +void LuaScriptingContext::ExecutionCountHook(lua_State* lua, lua_Debug* ar) { - if(_context->_timer.GetElapsedMS() > _timeout) { + if (_context->_timer.GetElapsedMS() > _timeout) + { luaL_error(lua, (std::string("Maximum execution time (") + std::to_string(_timeout) + " ms) exceeded.").c_str()); } } @@ -61,7 +68,7 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De int iErr = 0; _lua = luaL_newstate(); - + _context = this; LuaApi::SetContext(this); @@ -78,10 +85,13 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De luaL_requiref(_lua, "emu", LuaApi::GetLibrary, 1); Log("Loading script..."); - if((iErr = luaL_loadbufferx(_lua, scriptContent.c_str(), scriptContent.size(), ("@" + scriptName).c_str(), nullptr)) == 0) { + if ((iErr = luaL_loadbufferx(_lua, scriptContent.c_str(), scriptContent.size(), ("@" + scriptName).c_str(), + nullptr)) == 0) + { _timer.Reset(); lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); - if((iErr = lua_pcall(_lua, 0, LUA_MULTRET, 0)) == 0) { + if ((iErr = lua_pcall(_lua, 0, LUA_MULTRET, 0)) == 0) + { //Script loaded properly Log("Script loaded successfully."); _initDone = true; @@ -89,13 +99,15 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De } } - if(lua_isstring(_lua, -1)) { + if (lua_isstring(_lua, -1)) + { Log(lua_tostring(_lua, -1)); } return false; } -void LuaScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void LuaScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { ScriptingContext::UnregisterMemoryCallback(type, startAddr, endAddr, cpuType, reference); luaL_unref(_lua, LUA_REGISTRYINDEX, reference); @@ -107,18 +119,21 @@ void LuaScriptingContext::UnregisterEventCallback(EventType type, int reference) luaL_unref(_lua, LUA_REGISTRYINDEX, reference); } -void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) +void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) { - if(_callbacks[(int)type].empty()) { + if (_callbacks[(int)type].empty()) + { return; } _timer.Reset(); _context = this; - lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); + lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); LuaApi::SetContext(this); - for(MemoryCallback &callback: _callbacks[(int)type]) { - if(callback.Type != cpuType || addr < callback.StartAddress || addr > callback.EndAddress) { + for (MemoryCallback& callback : _callbacks[(int)type]) + { + if (callback.Type != cpuType || addr < callback.StartAddress || addr > callback.EndAddress) + { continue; } @@ -126,11 +141,15 @@ void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &val lua_rawgeti(_lua, LUA_REGISTRYINDEX, callback.Reference); lua_pushinteger(_lua, addr); lua_pushinteger(_lua, value); - if(lua_pcall(_lua, 2, LUA_MULTRET, 0) != 0) { + if (lua_pcall(_lua, 2, LUA_MULTRET, 0) != 0) + { Log(lua_tostring(_lua, -1)); - } else { + } + else + { int returnParamCount = lua_gettop(_lua) - top; - if(returnParamCount && lua_isinteger(_lua, -1)) { + if (returnParamCount && lua_isinteger(_lua, -1)) + { int newValue = (int)lua_tointeger(_lua, -1); value = (uint8_t)newValue; } @@ -141,21 +160,24 @@ void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &val int LuaScriptingContext::InternalCallEventCallback(EventType type) { - if(_eventCallbacks[(int)type].empty()) { + if (_eventCallbacks[(int)type].empty()) + { return 0; } _timer.Reset(); _context = this; - lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); + lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); LuaApi::SetContext(this); LuaCallHelper l(_lua); - for(int &ref : _eventCallbacks[(int)type]) { + for (int& ref : _eventCallbacks[(int)type]) + { lua_rawgeti(_lua, LUA_REGISTRYINDEX, ref); - if(lua_pcall(_lua, 0, 0, 0) != 0) { + if (lua_pcall(_lua, 0, 0, 0) != 0) + { Log(lua_tostring(_lua, -1)); } } return l.ReturnCount(); } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaScriptingContext.h b/Core/LuaScriptingContext.h index acc148e..5a9095f 100644 --- a/Core/LuaScriptingContext.h +++ b/Core/LuaScriptingContext.h @@ -20,7 +20,7 @@ private: static void ExecutionCountHook(lua_State* lua, lua_Debug* ar); protected: - void InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) override; + void InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) override; int InternalCallEventCallback(EventType type) override; public: @@ -30,7 +30,8 @@ public: static void SetScriptTimeout(uint32_t timeout); bool LoadScript(string scriptName, string scriptContent, Debugger* debugger) override; - - void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) override; + + void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) override; void UnregisterEventCallback(EventType type, int reference) override; }; diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp index 9a3369d..704d2ea 100644 --- a/Core/MemoryAccessCounter.cpp +++ b/Core/MemoryAccessCounter.cpp @@ -11,7 +11,7 @@ #include "Gameboy.h" #include "BaseCartridge.h" -MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) +MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console* console) { _debugger = debugger; _memoryManager = console->GetMemoryManager().get(); @@ -21,18 +21,21 @@ MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) _cx4 = console->GetCartridge()->GetCx4(); _gameboy = console->GetCartridge()->GetGameboy(); - for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) { + for (int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) + { uint32_t memSize = _debugger->GetMemoryDumper()->GetMemorySize((SnesMemoryType)i); _counters[i].reserve(memSize); - for(uint32_t j = 0; j < memSize; j++) { - _counters[i].push_back({ j }); + for (uint32_t j = 0; j < memSize; j++) + { + _counters[i].push_back({j}); } } } bool MemoryAccessCounter::IsAddressUninitialized(AddressInfo& addressInfo) { - if(!DebugUtilities::IsRomMemory(addressInfo.Type)) { + if (!DebugUtilities::IsRomMemory(addressInfo.Type)) + { return _counters[(int)addressInfo.Type][addressInfo.Address].WriteCount == 0; } return false; @@ -43,16 +46,18 @@ uint64_t MemoryAccessCounter::GetReadCount(AddressInfo& addressInfo) return _counters[(int)addressInfo.Type][addressInfo.Address].ReadCount; } -bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint64_t masterClock) +bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return false; } AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address]; counts.ReadCount++; counts.ReadStamp = masterClock; - if(counts.WriteCount == 0 && IsAddressUninitialized(addressInfo)) { + if (counts.WriteCount == 0 && IsAddressUninitialized(addressInfo)) + { //Mark address as read before being written to (if trying to read/execute) counts.UninitRead = true; return true; @@ -62,7 +67,8 @@ bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint64_t m void MemoryAccessCounter::ProcessMemoryWrite(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return; } @@ -73,7 +79,8 @@ void MemoryAccessCounter::ProcessMemoryWrite(AddressInfo& addressInfo, uint64_t void MemoryAccessCounter::ProcessMemoryExec(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return; } @@ -85,80 +92,100 @@ void MemoryAccessCounter::ProcessMemoryExec(AddressInfo& addressInfo, uint64_t m void MemoryAccessCounter::ResetCounts() { DebugBreakHelper helper(_debugger); - for(int i = 0; i < (int)SnesMemoryType::Register; i++) { - for(uint32_t j = 0; j < _counters[i].size(); j++) { - _counters[i][j] = { j }; + for (int i = 0; i < (int)SnesMemoryType::Register; i++) + { + for (uint32_t j = 0; j < _counters[i].size(); j++) + { + _counters[i][j] = {j}; } } } -void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, AddressCounters counts[]) +void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, + AddressCounters counts[]) { - switch(memoryType) { - case SnesMemoryType::CpuMemory: - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { + switch (memoryType) + { + case SnesMemoryType::CpuMemory: + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; + } + } + break; + + case SnesMemoryType::SpcMemory: + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _spc->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; + } + } + break; + + case SnesMemoryType::Sa1Memory: + if (_sa1) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _sa1->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::SpcMemory: - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _spc->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { + case SnesMemoryType::GsuMemory: + if (_gsu) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::Sa1Memory: - if(_sa1) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _sa1->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } + case SnesMemoryType::Cx4Memory: + if (_cx4) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _cx4->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::GsuMemory: - if(_gsu) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } + case SnesMemoryType::GameboyMemory: + if (_gameboy) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _gameboy->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::Cx4Memory: - if(_cx4) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _cx4->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } - } - } - break; - - case SnesMemoryType::GameboyMemory: - if(_gameboy) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _gameboy->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } - } - } - break; - - default: - memcpy(counts, _counters[(int)memoryType].data() + offset, length * sizeof(AddressCounters)); - break; + default: + memcpy(counts, _counters[(int)memoryType].data() + offset, length * sizeof(AddressCounters)); + break; } } diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h index ee45494..d80785c 100644 --- a/Core/MemoryAccessCounter.h +++ b/Core/MemoryAccessCounter.h @@ -38,10 +38,10 @@ private: Cx4* _cx4; Gameboy* _gameboy; - bool IsAddressUninitialized(AddressInfo &addressInfo); + bool IsAddressUninitialized(AddressInfo& addressInfo); public: - MemoryAccessCounter(Debugger *debugger, Console *console); + MemoryAccessCounter(Debugger* debugger, Console* console); uint64_t GetReadCount(AddressInfo& addressInfo); @@ -52,4 +52,4 @@ public: void ResetCounts(); void GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, AddressCounters counts[]); -}; \ No newline at end of file +}; diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index 0d0d48a..638eea1 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -29,214 +29,256 @@ MemoryDumper::MemoryDumper(Debugger* debugger) _cartridge = debugger->GetConsole()->GetCartridge().get(); } -void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t length) +void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t* buffer, uint32_t length) { - if(length > GetMemorySize(type)) { + if (length > GetMemorySize(type)) + { return; } uint8_t* dst = GetMemoryBuffer(type); - if(dst) { + if (dst) + { memcpy(dst, buffer, length); } } uint8_t* MemoryDumper::GetMemoryBuffer(SnesMemoryType type) { - switch(type) { - default: return nullptr; - case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom(); - case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam(); - case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRam(); - case SnesMemoryType::VideoRam: return _ppu->GetVideoRam(); - case SnesMemoryType::SpriteRam: return _ppu->GetSpriteRam(); - case SnesMemoryType::CGRam: return _ppu->GetCgRam(); - case SnesMemoryType::SpcRam: return _spc->GetSpcRam(); - case SnesMemoryType::SpcRom: return _spc->GetSpcRom(); + switch (type) + { + default: return nullptr; + case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom(); + case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam(); + case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRam(); + case SnesMemoryType::VideoRam: return _ppu->GetVideoRam(); + case SnesMemoryType::SpriteRam: return _ppu->GetSpriteRam(); + case SnesMemoryType::CGRam: return _ppu->GetCgRam(); + case SnesMemoryType::SpcRam: return _spc->GetSpcRam(); + case SnesMemoryType::SpcRom: return _spc->GetSpcRom(); - case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRom() : nullptr; - case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRom() : nullptr; - case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRam() : nullptr; + case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() + ? _cartridge->GetDsp()->DebugGetProgramRom() + : nullptr; + case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRom() : nullptr; + case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRam() : nullptr; - case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRam() : nullptr; - case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRam() : nullptr; - case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRam() : nullptr; - case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRam() : nullptr; - case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack() : nullptr; + case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() + ? _cartridge->GetSa1()->DebugGetInternalRam() + : nullptr; + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRam() : nullptr; + case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRam() : nullptr; + case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRam() : nullptr; + case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() + ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack() + : nullptr; - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbSpriteRam: - return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemory(type) : nullptr; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbSpriteRam: + return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemory(type) : nullptr; } } uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type) { - switch(type) { - default: return 0; - case SnesMemoryType::CpuMemory: return 0x1000000; - case SnesMemoryType::SpcMemory: return 0x10000; - case SnesMemoryType::Sa1Memory: return 0x1000000; - case SnesMemoryType::GsuMemory: return 0x1000000; - case SnesMemoryType::Cx4Memory: return 0x1000000; - case SnesMemoryType::GameboyMemory: return 0x10000; - case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize(); - case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize; - case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize(); - case SnesMemoryType::VideoRam: return Ppu::VideoRamSize; - case SnesMemoryType::SpriteRam: return Ppu::SpriteRamSize; - case SnesMemoryType::CGRam: return Ppu::CgRamSize; - case SnesMemoryType::SpcRam: return Spc::SpcRamSize; - case SnesMemoryType::SpcRom: return Spc::SpcRomSize; - case SnesMemoryType::Register: return 0x10000; + switch (type) + { + default: return 0; + case SnesMemoryType::CpuMemory: return 0x1000000; + case SnesMemoryType::SpcMemory: return 0x10000; + case SnesMemoryType::Sa1Memory: return 0x1000000; + case SnesMemoryType::GsuMemory: return 0x1000000; + case SnesMemoryType::Cx4Memory: return 0x1000000; + case SnesMemoryType::GameboyMemory: return 0x10000; + case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize(); + case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize; + case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize(); + case SnesMemoryType::VideoRam: return Ppu::VideoRamSize; + case SnesMemoryType::SpriteRam: return Ppu::SpriteRamSize; + case SnesMemoryType::CGRam: return Ppu::CgRamSize; + case SnesMemoryType::SpcRam: return Spc::SpcRamSize; + case SnesMemoryType::SpcRom: return Spc::SpcRomSize; + case SnesMemoryType::Register: return 0x10000; - case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRomSize() : 0; - case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRomSize() : 0; - case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0; - - case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRamSize() : 0; - case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0; - case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRamSize() : 0; - case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRamSize() : 0; - case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize() : 0; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbSpriteRam: - return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemorySize(type) : 0; + case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRomSize() : 0; + case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRomSize() : 0; + case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0; + + case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() + ? _cartridge->GetSa1()->DebugGetInternalRamSize() + : 0; + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0; + case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRamSize() : 0; + case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRamSize() : 0; + case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() + ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize() + : 0; + + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbSpriteRam: + return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemorySize(type) : 0; } } -void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer) +void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t* buffer) { - switch(type) { - case SnesMemoryType::CpuMemory: - for(int i = 0; i <= 0xFFFFFF; i+=0x1000) { - _memoryManager->PeekBlock(i, buffer+i); - } - break; + switch (type) + { + case SnesMemoryType::CpuMemory: + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _memoryManager->PeekBlock(i, buffer + i); + } + break; - case SnesMemoryType::SpcMemory: - for(int i = 0; i <= 0xFFFF; i++) { - buffer[i] = _spc->DebugRead(i); - } - break; - - case SnesMemoryType::Sa1Memory: - if(_cartridge->GetSa1()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetSa1()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } - } - break; + case SnesMemoryType::SpcMemory: + for (int i = 0; i <= 0xFFFF; i++) + { + buffer[i] = _spc->DebugRead(i); + } + break; - case SnesMemoryType::GsuMemory: - if(_cartridge->GetGsu()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetGsu()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } + case SnesMemoryType::Sa1Memory: + if (_cartridge->GetSa1()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetSa1()->GetMemoryMappings()->PeekBlock(i, buffer + i); } - break; + } + break; - case SnesMemoryType::Cx4Memory: - if(_cartridge->GetCx4()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetCx4()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } + case SnesMemoryType::GsuMemory: + if (_cartridge->GetGsu()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetGsu()->GetMemoryMappings()->PeekBlock(i, buffer + i); } - break; + } + break; - case SnesMemoryType::GameboyMemory: { - if(_cartridge->GetGameboy()) { + case SnesMemoryType::Cx4Memory: + if (_cartridge->GetCx4()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetCx4()->GetMemoryMappings()->PeekBlock(i, buffer + i); + } + } + break; + + case SnesMemoryType::GameboyMemory: + { + if (_cartridge->GetGameboy()) + { GbMemoryManager* memManager = _cartridge->GetGameboy()->GetMemoryManager(); - for(int i = 0; i <= 0xFFFF; i++) { + for (int i = 0; i <= 0xFFFF; i++) + { buffer[i] = memManager->DebugRead(i); } } break; } - default: - uint8_t* src = GetMemoryBuffer(type); - if(src) { - memcpy(buffer, src, GetMemorySize(type)); - } - break; + default: + uint8_t* src = GetMemoryBuffer(type); + if (src) + { + memcpy(buffer, src, GetMemorySize(type)); + } + break; } } void MemoryDumper::SetMemoryValues(SnesMemoryType memoryType, uint32_t address, uint8_t* data, uint32_t length) { DebugBreakHelper helper(_debugger); - for(uint32_t i = 0; i < length; i++) { - SetMemoryValue(memoryType, address+i, data[i], true); + for (uint32_t i = 0; i < length; i++) + { + SetMemoryValue(memoryType, address + i, data[i], true); } } void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, uint8_t value, bool disableSideEffects) { - if(address >= GetMemorySize(memoryType)) { + if (address >= GetMemorySize(memoryType)) + { return; } - if(disableSideEffects && memoryType <= DebugUtilities::GetLastCpuMemoryType()) { - AddressInfo addr = { (int32_t)address, memoryType }; + if (disableSideEffects && memoryType <= DebugUtilities::GetLastCpuMemoryType()) + { + AddressInfo addr = {(int32_t)address, memoryType}; addr = _debugger->GetAbsoluteAddress(addr); - if(addr.Address >= 0) { + if (addr.Address >= 0) + { SetMemoryValue(addr.Type, addr.Address, value, true); } return; } - auto invalidateCache = [=]() { - AddressInfo addr = { (int32_t)address, memoryType }; + auto invalidateCache = [=]() + { + AddressInfo addr = {(int32_t)address, memoryType}; _debugger->GetDisassembler()->InvalidateCache(addr, DebugUtilities::ToCpuType(memoryType)); }; - switch(memoryType) { - case SnesMemoryType::CpuMemory: _memoryManager->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); break; - case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::Cx4Memory: _cartridge->GetCx4()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::GameboyMemory: _cartridge->GetGameboy()->GetMemoryManager()->DebugWrite(address, value); break; + switch (memoryType) + { + case SnesMemoryType::CpuMemory: _memoryManager->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); + break; + case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::Cx4Memory: _cartridge->GetCx4()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::GameboyMemory: _cartridge->GetGameboy()->GetMemoryManager()->DebugWrite(address, value); + break; - default: - uint8_t* src = GetMemoryBuffer(memoryType); - if(src) { - src[address] = value; - invalidateCache(); - } - break; + default: + uint8_t* src = GetMemoryBuffer(memoryType); + if (src) + { + src[address] = value; + invalidateCache(); + } + break; } } uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects) { - if(address >= GetMemorySize(memoryType)) { + if (address >= GetMemorySize(memoryType)) + { return 0; } - switch(memoryType) { - case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address); - case SnesMemoryType::SpcMemory: return _spc->DebugRead(address); - case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::Cx4Memory: return _cartridge->GetCx4()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::GameboyMemory: return _cartridge->GetGameboy()->GetMemoryManager()->DebugRead(address); - - default: - uint8_t* src = GetMemoryBuffer(memoryType); - return src ? src[address] : 0; + switch (memoryType) + { + case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address); + case SnesMemoryType::SpcMemory: return _spc->DebugRead(address); + case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::Cx4Memory: return _cartridge->GetCx4()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::GameboyMemory: return _cartridge->GetGameboy()->GetMemoryManager()->DebugRead(address); + + default: + uint8_t* src = GetMemoryBuffer(memoryType); + return src ? src[address] : 0; } } @@ -248,9 +290,10 @@ uint16_t MemoryDumper::GetMemoryValueWord(SnesMemoryType memoryType, uint32_t ad return (msb << 8) | lsb; } -void MemoryDumper::SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, bool disableSideEffects) +void MemoryDumper::SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, + bool disableSideEffects) { DebugBreakHelper helper(_debugger); SetMemoryValue(memoryType, address, (uint8_t)value, disableSideEffects); SetMemoryValue(memoryType, address + 1, (uint8_t)(value >> 8), disableSideEffects); -} \ No newline at end of file +} diff --git a/Core/MemoryDumper.h b/Core/MemoryDumper.h index ec95ff3..fb41695 100644 --- a/Core/MemoryDumper.h +++ b/Core/MemoryDumper.h @@ -26,12 +26,12 @@ public: uint8_t* GetMemoryBuffer(SnesMemoryType type); uint32_t GetMemorySize(SnesMemoryType type); - void GetMemoryState(SnesMemoryType type, uint8_t *buffer); + void GetMemoryState(SnesMemoryType type, uint8_t* buffer); uint8_t GetMemoryValue(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects = true); uint16_t GetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects = true); void SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, bool disableSideEffects = true); void SetMemoryValue(SnesMemoryType memoryType, uint32_t address, uint8_t value, bool disableSideEffects = true); void SetMemoryValues(SnesMemoryType memoryType, uint32_t address, uint8_t* data, uint32_t length); - void SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t length); -}; \ No newline at end of file + void SetMemoryState(SnesMemoryType type, uint8_t* buffer, uint32_t length); +}; diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 44243c1..97d9ff6 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -20,7 +20,7 @@ #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" -void MemoryManager::Initialize(Console *console) +void MemoryManager::Initialize(Console* console) { _masterClock = 0; _openBus = 0; @@ -48,8 +48,10 @@ void MemoryManager::Initialize(Console *console) _workRam )); - for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) { - _workRamHandlers.push_back(unique_ptr(new RamHandler(_workRam, i, MemoryManager::WorkRamSize, SnesMemoryType::WorkRam))); + for (uint32_t i = 0; i < 128 * 1024; i += 0x1000) + { + _workRamHandlers.push_back( + unique_ptr(new RamHandler(_workRam, i, MemoryManager::WorkRamSize, SnesMemoryType::WorkRam))); } _mappings.RegisterHandler(0x7E, 0x7F, 0x0000, 0xFFFF, _workRamHandlers); @@ -87,37 +89,56 @@ void MemoryManager::Reset() void MemoryManager::GenerateMasterClockTable() { - for(int i = 0; i < 0x800; i++) { + for (int i = 0; i < 0x800; i++) + { uint8_t bank = (i & 0x300) >> 8; - if(bank == 1) { + if (bank == 1) + { //Banks $40-$7F - Slow _masterClockTable[i] = 8; - } else if(bank == 3) { + } + else if (bank == 3) + { //Banks $C0-$FF //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; - } else { + } + else + { //Banks $00-$3F and $80-$BF uint8_t page = (i & 0xFF); - if(page <= 0x1F) { + if (page <= 0x1F) + { //Slow _masterClockTable[i] = 8; - } else if(page >= 0x20 && page <= 0x3F) { + } + else if (page >= 0x20 && page <= 0x3F) + { //Fast _masterClockTable[i] = 6; - } else if(page == 0x40 || page == 0x41) { + } + else if (page == 0x40 || page == 0x41) + { //Extra slow _masterClockTable[i] = 12; - } else if(page >= 0x42 && page <= 0x5F) { + } + else if (page >= 0x42 && page <= 0x5F) + { //Fast _masterClockTable[i] = 6; - } else if(page >= 0x60 && page <= 0x7F) { + } + else if (page >= 0x60 && page <= 0x7F) + { //Slow _masterClockTable[i] = 8; - } else if(bank == 0) { + } + else if (bank == 0) + { //Slow _masterClockTable[i] = 8; - } else { + } + else + { //page >= $80 //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; @@ -149,28 +170,46 @@ void MemoryManager::IncMasterClock8() void MemoryManager::IncMasterClock40() { - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); } void MemoryManager::IncMasterClockStartup() { - for(int i = 0; i < 182 / 2; i++) { + for (int i = 0; i < 182 / 2; i++) + { Exec(); } } void MemoryManager::IncrementMasterClockValue(uint16_t cyclesToRun) { - switch(cyclesToRun) { - case 12: Exec(); - case 10: Exec(); - case 8: Exec(); - case 6: Exec(); - case 4: Exec(); - case 2: Exec(); + switch (cyclesToRun) + { + case 12: Exec(); + case 10: Exec(); + case 8: Exec(); + case 6: Exec(); + case 4: Exec(); + case 2: Exec(); } } @@ -179,11 +218,13 @@ void MemoryManager::Exec() _masterClock += 2; _hClock += 2; - if(_hClock == _nextEventClock) { + if (_hClock == _nextEventClock) + { ProcessEvent(); - } - - if((_hClock & 0x03) == 0) { + } + + if ((_hClock & 0x03) == 0) + { _console->ProcessPpuCycle(); _regs->ProcessIrqCounters(); } @@ -193,48 +234,58 @@ void MemoryManager::Exec() void MemoryManager::ProcessEvent() { - switch(_nextEvent) { - case SnesEventType::HdmaInit: - _console->GetDmaController()->BeginHdmaInit(); - _nextEvent = SnesEventType::DramRefresh; - _nextEventClock = _dramRefreshPosition; - break; + switch (_nextEvent) + { + case SnesEventType::HdmaInit: + _console->GetDmaController()->BeginHdmaInit(); + _nextEvent = SnesEventType::DramRefresh; + _nextEventClock = _dramRefreshPosition; + break; - case SnesEventType::DramRefresh: - IncMasterClock40(); - _cpu->IncreaseCycleCount<5>(); + case SnesEventType::DramRefresh: + IncMasterClock40(); + _cpu->IncreaseCycleCount<5>(); - if(_ppu->GetScanline() < _ppu->GetVblankStart()) { - _nextEvent = SnesEventType::HdmaStart; - _nextEventClock = 276 * 4; - } else { - _nextEvent = SnesEventType::EndOfScanline; - _nextEventClock = 1360; - } - break; - - case SnesEventType::HdmaStart: - _console->GetDmaController()->BeginHdmaTransfer(); + if (_ppu->GetScanline() < _ppu->GetVblankStart()) + { + _nextEvent = SnesEventType::HdmaStart; + _nextEventClock = 276 * 4; + } + else + { _nextEvent = SnesEventType::EndOfScanline; _nextEventClock = 1360; - break; + } + break; - case SnesEventType::EndOfScanline: - if(_ppu->ProcessEndOfScanline(_hClock)) { - _hClock = 0; + case SnesEventType::HdmaStart: + _console->GetDmaController()->BeginHdmaTransfer(); + _nextEvent = SnesEventType::EndOfScanline; + _nextEventClock = 1360; + break; - if(_ppu->GetScanline() == 0) { - _nextEvent = SnesEventType::HdmaInit; - _nextEventClock = 12 + (_masterClock & 0x07); - } else { - _dramRefreshPosition = 538 - (_masterClock & 0x07); - _nextEvent = SnesEventType::DramRefresh; - _nextEventClock = _dramRefreshPosition; - } - } else { - _nextEventClock += 2; + case SnesEventType::EndOfScanline: + if (_ppu->ProcessEndOfScanline(_hClock)) + { + _hClock = 0; + + if (_ppu->GetScanline() == 0) + { + _nextEvent = SnesEventType::HdmaInit; + _nextEventClock = 12 + (_masterClock & 0x07); } - break; + else + { + _dramRefreshPosition = 538 - (_masterClock & 0x07); + _nextEvent = SnesEventType::DramRefresh; + _nextEventClock = _dramRefreshPosition; + } + } + else + { + _nextEventClock += 2; + } + break; } } @@ -243,12 +294,15 @@ uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type) IncrementMasterClockValue(_cpuSpeed - 4); uint8_t value; - IMemoryHandler *handler = _mappings.GetHandler(addr); - if(handler) { + IMemoryHandler* handler = _mappings.GetHandler(addr); + if (handler) + { value = handler->Read(addr); _memTypeBusA = handler->GetMemoryType(); _openBus = value; - } else { + } + else + { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); @@ -267,26 +321,38 @@ uint8_t MemoryManager::ReadDma(uint32_t addr, bool forBusA) uint8_t value; IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { - if(forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { + if (handler) + { + if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) + { //Trying to read from bus B using bus A returns open bus value = _openBus; - } else if(handler == _registerHandlerA.get()) { + } + else if (handler == _registerHandlerA.get()) + { uint16_t regAddr = addr & 0xFFFF; - if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { + if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) + { //Trying to read the DMA controller with DMA returns open bus value = _openBus; - } else { + } + else + { value = handler->Read(addr); } - } else { + } + else + { value = handler->Read(addr); - if(handler != _registerHandlerB.get()) { + if (handler != _registerHandlerB.get()) + { _memTypeBusA = handler->GetMemoryType(); } } _openBus = value; - } else { + } + else + { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); @@ -306,7 +372,7 @@ uint16_t MemoryManager::PeekWord(uint32_t addr) return _mappings.PeekWord(addr); } -void MemoryManager::PeekBlock(uint32_t addr, uint8_t *dest) +void MemoryManager::PeekBlock(uint32_t addr, uint8_t* dest) { _mappings.PeekBlock(addr, dest); } @@ -317,10 +383,13 @@ void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type _console->ProcessMemoryWrite(addr, value, type); IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { + if (handler) + { handler->Write(addr, value); _memTypeBusA = handler->GetMemoryType(); - } else { + } + else + { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } @@ -332,23 +401,35 @@ void MemoryManager::WriteDma(uint32_t addr, uint8_t value, bool forBusA) _console->ProcessMemoryWrite(addr, value, MemoryOperationType::DmaWrite); IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { - if(forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { + if (handler) + { + if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) + { //Trying to write to bus B using bus A does nothing - } else if(handler == _registerHandlerA.get()) { + } + else if (handler == _registerHandlerA.get()) + { uint16_t regAddr = addr & 0xFFFF; - if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { + if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) + { //Trying to write to the DMA controller with DMA does nothing - } else { + } + else + { handler->Write(addr, value); } - } else { + } + else + { handler->Write(addr, value); - if(handler != _registerHandlerB.get()) { + if (handler != _registerHandlerB.get()) + { _memTypeBusA = handler->GetMemoryType(); } } - } else { + } + else + { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } @@ -368,7 +449,7 @@ uint16_t MemoryManager::GetHClock() return _hClock; } -uint8_t * MemoryManager::DebugGetWorkRam() +uint8_t* MemoryManager::DebugGetWorkRam() { return _workRam; } @@ -410,12 +491,13 @@ bool MemoryManager::IsWorkRam(uint32_t cpuAddress) return handler && handler->GetMemoryType() == SnesMemoryType::WorkRam; } -void MemoryManager::Serialize(Serializer &s) +void MemoryManager::Serialize(Serializer& s) { s.Stream(_masterClock, _openBus, _cpuSpeed, _hClock, _dramRefreshPosition); s.StreamArray(_workRam, MemoryManager::WorkRamSize); - if(s.GetVersion() < 8) { + if (s.GetVersion() < 8) + { bool unusedHasEvent[1369]; s.StreamArray(unusedHasEvent, sizeof(unusedHasEvent)); } diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 0862845..66d5b37 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -35,12 +35,12 @@ private: shared_ptr _registerHandlerA; shared_ptr _registerHandlerB; - InternalRegisters *_regs; + InternalRegisters* _regs; Ppu* _ppu; Cpu* _cpu; BaseCartridge* _cart; CheatManager* _cheatManager; - uint8_t *_workRam; + uint8_t* _workRam; uint64_t _masterClock = 0; uint16_t _hClock = 0; @@ -80,7 +80,7 @@ public: uint8_t Peek(uint32_t addr); uint16_t PeekWord(uint32_t addr); - void PeekBlock(uint32_t addr, uint8_t * dest); + void PeekBlock(uint32_t addr, uint8_t* dest); void Write(uint32_t addr, uint8_t value, MemoryOperationType type); void WriteDma(uint32_t addr, uint8_t value, bool forBusA); @@ -100,5 +100,5 @@ public: bool IsRegister(uint32_t cpuAddress); bool IsWorkRam(uint32_t cpuAddress); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/MemoryMappings.cpp b/Core/MemoryMappings.cpp index 9ce2930..1bf50c5 100644 --- a/Core/MemoryMappings.cpp +++ b/Core/MemoryMappings.cpp @@ -2,36 +2,46 @@ #include "MemoryMappings.h" #include "IMemoryHandler.h" -void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, vector> &handlers, uint16_t pageIncrement, uint16_t startPageNumber) +void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, + vector>& handlers, uint16_t pageIncrement, + uint16_t startPageNumber) { - if(handlers.empty()) { + if (handlers.empty()) + { return; } startPageNumber %= handlers.size(); uint32_t pageNumber = startPageNumber; - for(uint32_t i = startBank; i <= endBank; i++) { + for (uint32_t i = startBank; i <= endBank; i++) + { pageNumber += pageIncrement; - for(uint32_t j = startPage; j <= endPage; j += 0x1000) { + for (uint32_t j = startPage; j <= endPage; j += 0x1000) + { _handlers[(i << 4) | (j >> 12)] = handlers[pageNumber].get(); //MessageManager::Log("Map [$" + HexUtilities::ToHex(i) + ":" + HexUtilities::ToHex(j)[1] + "xxx] to page number " + HexUtilities::ToHex(pageNumber)); pageNumber++; - if(pageNumber >= handlers.size()) { + if (pageNumber >= handlers.size()) + { pageNumber = 0; } } } } -void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, IMemoryHandler* handler) +void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, + IMemoryHandler* handler) { - if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF || startBank > endBank || startAddr > endAddr) { + if ((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF || startBank > endBank || startAddr > endAddr) + { throw std::runtime_error("invalid start/end address"); } - for(uint32_t bank = startBank; bank <= endBank; bank++) { - for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) { + for (uint32_t bank = startBank; bank <= endBank; bank++) + { + for (uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) + { /*if(_handlers[addr >> 12]) { throw std::runtime_error("handler already set"); }*/ @@ -49,10 +59,13 @@ IMemoryHandler* MemoryMappings::GetHandler(uint32_t addr) AddressInfo MemoryMappings::GetAbsoluteAddress(uint32_t addr) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { return handler->GetAbsoluteAddress(addr); - } else { - return { -1, SnesMemoryType::CpuMemory }; + } + else + { + return {-1, SnesMemoryType::CpuMemory}; } } @@ -60,20 +73,26 @@ int MemoryMappings::GetRelativeAddress(AddressInfo& absAddress, uint8_t startBan { uint16_t startPosition = startBank << 4; - for(int i = startPosition; i <= 0xFFF; i++) { + for (int i = startPosition; i <= 0xFFF; i++) + { IMemoryHandler* handler = GetHandler(i << 12); - if(handler) { + if (handler) + { AddressInfo addrInfo = handler->GetAbsoluteAddress(absAddress.Address & 0xFFF); - if(addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) { + if (addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) + { return (i << 12) | (absAddress.Address & 0xFFF); } } } - for(int i = 0; i < startPosition; i++) { + for (int i = 0; i < startPosition; i++) + { IMemoryHandler* handler = GetHandler(i << 12); - if(handler) { + if (handler) + { AddressInfo addrInfo = handler->GetAbsoluteAddress(absAddress.Address & 0xFFF); - if(addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) { + if (addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) + { return (i << 12) | (absAddress.Address & 0xFFF); } } @@ -86,7 +105,8 @@ uint8_t MemoryMappings::Peek(uint32_t addr) //Read, without triggering side-effects uint8_t value = 0; IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { value = handler->Peek(addr); } return value; @@ -99,12 +119,15 @@ uint16_t MemoryMappings::PeekWord(uint32_t addr) return (msb << 8) | lsb; } -void MemoryMappings::PeekBlock(uint32_t addr, uint8_t *dest) +void MemoryMappings::PeekBlock(uint32_t addr, uint8_t* dest) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { handler->PeekBlock(addr & ~0xFFF, dest); - } else { + } + else + { memset(dest, 0, 0x1000); } } @@ -112,7 +135,8 @@ void MemoryMappings::PeekBlock(uint32_t addr, uint8_t *dest) void MemoryMappings::DebugWrite(uint32_t addr, uint8_t value) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { handler->Write(addr, value); } } diff --git a/Core/MemoryMappings.h b/Core/MemoryMappings.h index 489f358..2ef8137 100644 --- a/Core/MemoryMappings.h +++ b/Core/MemoryMappings.h @@ -10,8 +10,11 @@ private: IMemoryHandler* _handlers[0x100 * 0x10] = {}; public: - void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, vector>& handlers, uint16_t pageIncrement = 0, uint16_t startPageNumber = 0); - void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, IMemoryHandler* handler); + void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, + vector>& handlers, uint16_t pageIncrement = 0, + uint16_t startPageNumber = 0); + void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, + IMemoryHandler* handler); IMemoryHandler* GetHandler(uint32_t addr); AddressInfo GetAbsoluteAddress(uint32_t addr); @@ -19,7 +22,7 @@ public: uint8_t Peek(uint32_t addr); uint16_t PeekWord(uint32_t addr); - void PeekBlock(uint32_t addr, uint8_t * dest); + void PeekBlock(uint32_t addr, uint8_t* dest); void DebugWrite(uint32_t addr, uint8_t value); }; diff --git a/Core/MesenMovie.cpp b/Core/MesenMovie.cpp index 93aef7b..ba6155e 100644 --- a/Core/MesenMovie.cpp +++ b/Core/MesenMovie.cpp @@ -29,12 +29,15 @@ MesenMovie::~MesenMovie() void MesenMovie::Stop() { - if(_playing) { - if(!_forTest) { + if (_playing) + { + if (!_forTest) + { MessageManager::DisplayMessage("Movies", "MovieEnded"); } - if(_console->GetSettings()->GetPreferences().PauseOnMovieEnd) { + if (_console->GetSettings()->GetPreferences().PauseOnMovieEnd) + { _console->Pause(); } @@ -45,20 +48,24 @@ void MesenMovie::Stop() _console->GetControlManager()->UnregisterInputProvider(this); } -bool MesenMovie::SetInput(BaseControlDevice *device) +bool MesenMovie::SetInput(BaseControlDevice* device) { uint32_t inputRowIndex = _console->GetControlManager()->GetPollCounter(); _lastPollCounter = inputRowIndex; - if(_inputData.size() > inputRowIndex && _inputData[inputRowIndex].size() > _deviceIndex) { + if (_inputData.size() > inputRowIndex && _inputData[inputRowIndex].size() > _deviceIndex) + { device->SetTextState(_inputData[inputRowIndex][_deviceIndex]); _deviceIndex++; - if(_deviceIndex >= _inputData[inputRowIndex].size()) { + if (_deviceIndex >= _inputData[inputRowIndex].size()) + { //Move to the next frame's data _deviceIndex = 0; } - } else { + } + else + { _console->GetMovieManager()->Stop(); } return true; @@ -78,13 +85,14 @@ vector MesenMovie::LoadBattery(string extension) void MesenMovie::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded) { + if (type == ConsoleNotificationType::GameLoaded) + { _console->GetControlManager()->RegisterInputProvider(this); _console->GetControlManager()->SetPollCounter(_lastPollCounter); } } -bool MesenMovie::Play(VirtualFile &file) +bool MesenMovie::Play(VirtualFile& file) { _movieFile = file; @@ -95,19 +103,23 @@ bool MesenMovie::Play(VirtualFile &file) _reader->LoadArchive(ss); stringstream settingsData, inputData; - if(!_reader->GetStream("GameSettings.txt", settingsData)) { + if (!_reader->GetStream("GameSettings.txt", settingsData)) + { MessageManager::Log("[Movie] File not found: GameSettings.txt"); return false; } - if(!_reader->GetStream("Input.txt", inputData)) { + if (!_reader->GetStream("Input.txt", inputData)) + { MessageManager::Log("[Movie] File not found: Input.txt"); return false; } - while(inputData) { + while (inputData) + { string line; std::getline(inputData, line); - if(line.substr(0, 1) == "|") { + if (line.substr(0, 1) == "|") + { _inputData.push_back(StringUtilities::Split(line.substr(1), '|')); } } @@ -115,9 +127,9 @@ bool MesenMovie::Play(VirtualFile &file) _deviceIndex = 0; ParseSettings(settingsData); - + _console->Lock(); - + _console->GetBatteryManager()->SetBatteryProvider(shared_from_this()); _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); ApplySettings(); @@ -127,8 +139,9 @@ bool MesenMovie::Play(VirtualFile &file) //bool autoConfigureInput = _console->GetSettings()->CheckFlag(EmulationFlags::AutoConfigureInput); //_console->GetSettings()->ClearFlags(EmulationFlags::AutoConfigureInput); - ControlManager *controlManager = _console->GetControlManager().get(); - if(controlManager) { + ControlManager* controlManager = _console->GetControlManager().get(); + if (controlManager) + { //ControlManager can be empty if no game is loaded controlManager->SetPollCounter(0); } @@ -145,20 +158,27 @@ bool MesenMovie::Play(VirtualFile &file) _originalCheats = _console->GetCheatManager()->GetCheats(); controlManager->UpdateControlDevices(); - if(!_forTest) { + if (!_forTest) + { _console->PowerCycle(); - } else { + } + else + { controlManager->RegisterInputProvider(this); } - LoadCheats(); + LoadCheats(); stringstream saveStateData; - if(_reader->GetStream("SaveState.mss", saveStateData)) { - if(!_console->GetSaveStateManager()->LoadState(saveStateData, true)) { + if (_reader->GetStream("SaveState.mss", saveStateData)) + { + if (!_console->GetSaveStateManager()->LoadState(saveStateData, true)) + { _console->Resume(); return false; - } else { + } + else + { _console->GetControlManager()->SetPollCounter(0); } } @@ -170,32 +190,40 @@ bool MesenMovie::Play(VirtualFile &file) return true; } -template -T FromString(string name, const vector &enumNames, T defaultValue) +template +T FromString(string name, const vector& enumNames, T defaultValue) { - for(size_t i = 0; i < enumNames.size(); i++) { - if(name == enumNames[i]) { + for (size_t i = 0; i < enumNames.size(); i++) + { + if (name == enumNames[i]) + { return (T)i; } } return defaultValue; } -void MesenMovie::ParseSettings(stringstream &data) +void MesenMovie::ParseSettings(stringstream& data) { - while(!data.eof()) { + while (!data.eof()) + { string line; std::getline(data, line); - if(!line.empty()) { + if (!line.empty()) + { size_t index = line.find_first_of(' '); - if(index != string::npos) { + if (index != string::npos) + { string name = line.substr(0, index); string value = line.substr(index + 1); - if(name == "Cheat") { + if (name == "Cheat") + { _cheats.push_back(value); - } else { + } + else + { _settings[name] = value; } } @@ -242,15 +270,22 @@ void MesenMovie::ApplySettings() EmulationConfig emuConfig = settings->GetEmulationConfig(); InputConfig inputConfig = settings->GetInputConfig(); - inputConfig.Controllers[0].Type = FromString(LoadString(_settings, MovieKeys::Controller1), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[1].Type = FromString(LoadString(_settings, MovieKeys::Controller2), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[2].Type = FromString(LoadString(_settings, MovieKeys::Controller3), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[3].Type = FromString(LoadString(_settings, MovieKeys::Controller4), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[4].Type = FromString(LoadString(_settings, MovieKeys::Controller5), ControllerTypeNames, ControllerType::None); + inputConfig.Controllers[0].Type = FromString(LoadString(_settings, MovieKeys::Controller1), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[1].Type = FromString(LoadString(_settings, MovieKeys::Controller2), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[2].Type = FromString(LoadString(_settings, MovieKeys::Controller3), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[3].Type = FromString(LoadString(_settings, MovieKeys::Controller4), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[4].Type = FromString(LoadString(_settings, MovieKeys::Controller5), ControllerTypeNames, + ControllerType::None); emuConfig.Region = FromString(LoadString(_settings, MovieKeys::Region), ConsoleRegionNames, ConsoleRegion::Ntsc); - if(!_forTest) { - emuConfig.RamPowerOnState = FromString(LoadString(_settings, MovieKeys::RamPowerOnState), RamStateNames, RamState::AllOnes); + if (!_forTest) + { + emuConfig.RamPowerOnState = FromString(LoadString(_settings, MovieKeys::RamPowerOnState), RamStateNames, + RamState::AllOnes); } emuConfig.PpuExtraScanlinesAfterNmi = LoadInt(_settings, MovieKeys::ExtraScanlinesAfterNmi); emuConfig.PpuExtraScanlinesBeforeNmi = LoadInt(_settings, MovieKeys::ExtraScanlinesBeforeNmi); @@ -260,44 +295,61 @@ void MesenMovie::ApplySettings() settings->SetInputConfig(inputConfig); } -uint32_t MesenMovie::LoadInt(std::unordered_map &settings, string name, uint32_t defaultValue) +uint32_t MesenMovie::LoadInt(std::unordered_map& settings, string name, uint32_t defaultValue) { auto result = settings.find(name); - if(result != settings.end()) { - try { + if (result != settings.end()) + { + try + { return (uint32_t)std::stoul(result->second); - } catch(std::exception&) { + } + catch (std::exception&) + { MessageManager::Log("[Movies] Invalid value for tag: " + name); return defaultValue; } - } else { + } + else + { return defaultValue; } } -bool MesenMovie::LoadBool(std::unordered_map &settings, string name) +bool MesenMovie::LoadBool(std::unordered_map& settings, string name) { auto result = settings.find(name); - if(result != settings.end()) { - if(result->second == "true") { + if (result != settings.end()) + { + if (result->second == "true") + { return true; - } else if(result->second == "false") { + } + else if (result->second == "false") + { return false; - } else { + } + else + { MessageManager::Log("[Movies] Invalid value for tag: " + name); return false; } - } else { + } + else + { return false; } } -string MesenMovie::LoadString(std::unordered_map &settings, string name) +string MesenMovie::LoadString(std::unordered_map& settings, string name) { auto result = settings.find(name); - if(result != settings.end()) { + if (result != settings.end()) + { return result->second; - } else { + } + else + { return ""; } } @@ -305,24 +357,29 @@ string MesenMovie::LoadString(std::unordered_map &settings, stri void MesenMovie::LoadCheats() { vector cheats; - for(string cheatData : _cheats) { + for (string cheatData : _cheats) + { CheatCode code; - if(LoadCheat(cheatData, code)) { + if (LoadCheat(cheatData, code)) + { cheats.push_back(code); } } _console->GetCheatManager()->SetCheats(cheats); } -bool MesenMovie::LoadCheat(string cheatData, CheatCode &code) +bool MesenMovie::LoadCheat(string cheatData, CheatCode& code) { vector data = StringUtilities::Split(cheatData, ' '); - if(data.size() == 2) { + if (data.size() == 2) + { code.Address = HexUtilities::FromHex(data[0]); code.Value = HexUtilities::FromHex(data[1]); return true; - } else { + } + else + { MessageManager::Log("[Movie] Invalid cheat definition: " + cheatData); } return false; diff --git a/Core/MesenMovie.h b/Core/MesenMovie.h index f1cc7fa..74c2ff0 100644 --- a/Core/MesenMovie.h +++ b/Core/MesenMovie.h @@ -10,7 +10,8 @@ class ZipReader; class Console; struct CheatCode; -class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, public std::enable_shared_from_this +class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, + public std::enable_shared_from_this { private: shared_ptr _console; @@ -28,23 +29,23 @@ private: bool _forTest; private: - void ParseSettings(stringstream &data); + void ParseSettings(stringstream& data); void ApplySettings(); bool LoadGame(); void Stop(); - uint32_t LoadInt(std::unordered_map &settings, string name, uint32_t defaultValue = 0); - bool LoadBool(std::unordered_map &settings, string name); - string LoadString(std::unordered_map &settings, string name); + uint32_t LoadInt(std::unordered_map& settings, string name, uint32_t defaultValue = 0); + bool LoadBool(std::unordered_map& settings, string name); + string LoadString(std::unordered_map& settings, string name); void LoadCheats(); - bool LoadCheat(string cheatData, CheatCode &code); + bool LoadCheat(string cheatData, CheatCode& code); public: MesenMovie(shared_ptr console, bool silent); virtual ~MesenMovie(); - bool Play(VirtualFile &file) override; + bool Play(VirtualFile& file) override; bool SetInput(BaseControlDevice* device) override; bool IsPlaying() override; @@ -52,5 +53,5 @@ public: vector LoadBattery(string extension) override; //Inherited via INotificationListener - void ProcessNotification(ConsoleNotificationType type, void * parameter) override; -}; \ No newline at end of file + void ProcessNotification(ConsoleNotificationType type, void* parameter) override; +}; diff --git a/Core/MessageManager.cpp b/Core/MessageManager.cpp index c5973af..6e98e73 100644 --- a/Core/MessageManager.cpp +++ b/Core/MessageManager.cpp @@ -2,80 +2,86 @@ #include "MessageManager.h" std::unordered_map MessageManager::_enResources = { - { "Cheats", u8"Cheats" }, - { "Debug", u8"Debug" }, - { "EmulationSpeed", u8"Emulation Speed" }, - { "ClockRate", u8"Clock Rate" }, - { "Error", u8"Error" }, - { "GameInfo", u8"Game Info" }, - { "GameLoaded", u8"Game loaded" }, - { "Input", u8"Input" }, - { "Patch", u8"Patch" }, - { "Movies", u8"Movies" }, - { "NetPlay", u8"Net Play" }, - { "Overclock", u8"Overclock" }, - { "Region", u8"Region" }, - { "SaveStates", u8"Save States" }, - { "ScreenshotSaved", u8"Screenshot Saved" }, - { "SoundRecorder", u8"Sound Recorder" }, - { "Test", u8"Test" }, - { "VideoRecorder", u8"Video Recorder" }, + {"Cheats", u8"Cheats"}, + {"Debug", u8"Debug"}, + {"EmulationSpeed", u8"Emulation Speed"}, + {"ClockRate", u8"Clock Rate"}, + {"Error", u8"Error"}, + {"GameInfo", u8"Game Info"}, + {"GameLoaded", u8"Game loaded"}, + {"Input", u8"Input"}, + {"Patch", u8"Patch"}, + {"Movies", u8"Movies"}, + {"NetPlay", u8"Net Play"}, + {"Overclock", u8"Overclock"}, + {"Region", u8"Region"}, + {"SaveStates", u8"Save States"}, + {"ScreenshotSaved", u8"Screenshot Saved"}, + {"SoundRecorder", u8"Sound Recorder"}, + {"Test", u8"Test"}, + {"VideoRecorder", u8"Video Recorder"}, - { "ApplyingPatch", u8"Applying patch: %1" }, - { "CheatApplied", u8"1 cheat applied." }, - { "CheatsApplied", u8"%1 cheats applied." }, - { "CheatsDisabled", u8"All cheats disabled." }, - { "CoinInsertedSlot", u8"Coin inserted (slot %1)" }, - { "ConnectedToServer", u8"Connected to server." }, - { "ConnectedAsPlayer", u8"Connected as player %1" }, - { "ConnectedAsSpectator", u8"Connected as spectator." }, - { "ConnectionLost", u8"Connection to server lost." }, - { "CouldNotConnect", u8"Could not connect to the server." }, - { "CouldNotInitializeAudioSystem", u8"Could not initialize audio system" }, - { "CouldNotFindRom", u8"Could not find matching game ROM. (%1)" }, - { "CouldNotWriteToFile", u8"Could not write to file: %1" }, - { "CouldNotLoadFile", u8"Could not load file: %1" }, - { "EmulationMaximumSpeed", u8"Maximum speed" }, - { "EmulationSpeedPercent", u8"%1%" }, - { "FdsDiskInserted", u8"Disk %1 Side %2 inserted." }, - { "Frame", u8"Frame" }, - { "GameCrash", u8"Game has crashed (%1)" }, - { "KeyboardModeDisabled", u8"Keyboard mode disabled." }, - { "KeyboardModeEnabled", u8"Keyboard mode enabled." }, - { "Lag", u8"Lag" }, - { "Mapper", u8"Mapper: %1, SubMapper: %2" }, - { "MovieEnded", u8"Movie ended." }, - { "MovieInvalid", u8"Invalid movie file." }, - { "MovieMissingRom", u8"Missing ROM required (%1) to play movie." }, - { "MovieNewerVersion", u8"Cannot load movies created by a more recent version of Mesen-S. Please download the latest version." }, - { "MovieIncompatibleVersion", u8"This movie is incompatible with this version of Mesen-S." }, - { "MoviePlaying", u8"Playing movie: %1" }, - { "MovieRecordingTo", u8"Recording to: %1" }, - { "MovieSaved", u8"Movie saved to file: %1" }, - { "NetplayVersionMismatch", u8"%1 is not running the same version of Mesen-S and has been disconnected." }, - { "NetplayNotAllowed", u8"This action is not allowed while connected to a server." }, - { "OverclockEnabled", u8"Overclocking enabled." }, - { "OverclockDisabled", u8"Overclocking disabled." }, - { "PrgSizeWarning", u8"PRG size is smaller than 32kb" }, - { "SaveStateEmpty", u8"Slot is empty." }, - { "SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen-S." }, - { "SaveStateInvalidFile", u8"Invalid save state file." }, - { "SaveStateWrongSystemSnes", u8"Error: State cannot be loaded (wrong console type: SNES)" }, - { "SaveStateWrongSystemGb", u8"Error: State cannot be loaded (wrong console type: Game Boy)" }, - { "SaveStateLoaded", u8"State #%1 loaded." }, - { "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." }, - { "SaveStateNewerVersion", u8"Cannot load save states created by a more recent version of Mesen-S. Please download the latest version." }, - { "SaveStateSaved", u8"State #%1 saved." }, - { "SaveStateSlotSelected", u8"Slot #%1 selected." }, - { "ScanlineTimingWarning", u8"PPU timing has been changed." }, - { "ServerStarted", u8"Server started (Port: %1)" }, - { "ServerStopped", u8"Server stopped" }, - { "SoundRecorderStarted", u8"Recording to: %1" }, - { "SoundRecorderStopped", u8"Recording saved to: %1" }, - { "TestFileSavedTo", u8"Test file saved to: %1" }, - { "UnsupportedMapper", u8"Unsupported mapper (%1), cannot load game." }, - { "VideoRecorderStarted", u8"Recording to: %1" }, - { "VideoRecorderStopped", u8"Recording saved to: %1" }, + {"ApplyingPatch", u8"Applying patch: %1"}, + {"CheatApplied", u8"1 cheat applied."}, + {"CheatsApplied", u8"%1 cheats applied."}, + {"CheatsDisabled", u8"All cheats disabled."}, + {"CoinInsertedSlot", u8"Coin inserted (slot %1)"}, + {"ConnectedToServer", u8"Connected to server."}, + {"ConnectedAsPlayer", u8"Connected as player %1"}, + {"ConnectedAsSpectator", u8"Connected as spectator."}, + {"ConnectionLost", u8"Connection to server lost."}, + {"CouldNotConnect", u8"Could not connect to the server."}, + {"CouldNotInitializeAudioSystem", u8"Could not initialize audio system"}, + {"CouldNotFindRom", u8"Could not find matching game ROM. (%1)"}, + {"CouldNotWriteToFile", u8"Could not write to file: %1"}, + {"CouldNotLoadFile", u8"Could not load file: %1"}, + {"EmulationMaximumSpeed", u8"Maximum speed"}, + {"EmulationSpeedPercent", u8"%1%"}, + {"FdsDiskInserted", u8"Disk %1 Side %2 inserted."}, + {"Frame", u8"Frame"}, + {"GameCrash", u8"Game has crashed (%1)"}, + {"KeyboardModeDisabled", u8"Keyboard mode disabled."}, + {"KeyboardModeEnabled", u8"Keyboard mode enabled."}, + {"Lag", u8"Lag"}, + {"Mapper", u8"Mapper: %1, SubMapper: %2"}, + {"MovieEnded", u8"Movie ended."}, + {"MovieInvalid", u8"Invalid movie file."}, + {"MovieMissingRom", u8"Missing ROM required (%1) to play movie."}, + { + "MovieNewerVersion", + u8"Cannot load movies created by a more recent version of Mesen-S. Please download the latest version." + }, + {"MovieIncompatibleVersion", u8"This movie is incompatible with this version of Mesen-S."}, + {"MoviePlaying", u8"Playing movie: %1"}, + {"MovieRecordingTo", u8"Recording to: %1"}, + {"MovieSaved", u8"Movie saved to file: %1"}, + {"NetplayVersionMismatch", u8"%1 is not running the same version of Mesen-S and has been disconnected."}, + {"NetplayNotAllowed", u8"This action is not allowed while connected to a server."}, + {"OverclockEnabled", u8"Overclocking enabled."}, + {"OverclockDisabled", u8"Overclocking disabled."}, + {"PrgSizeWarning", u8"PRG size is smaller than 32kb"}, + {"SaveStateEmpty", u8"Slot is empty."}, + {"SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen-S."}, + {"SaveStateInvalidFile", u8"Invalid save state file."}, + {"SaveStateWrongSystemSnes", u8"Error: State cannot be loaded (wrong console type: SNES)"}, + {"SaveStateWrongSystemGb", u8"Error: State cannot be loaded (wrong console type: Game Boy)"}, + {"SaveStateLoaded", u8"State #%1 loaded."}, + {"SaveStateMissingRom", u8"Missing ROM required (%1) to load save state."}, + { + "SaveStateNewerVersion", + u8"Cannot load save states created by a more recent version of Mesen-S. Please download the latest version." + }, + {"SaveStateSaved", u8"State #%1 saved."}, + {"SaveStateSlotSelected", u8"Slot #%1 selected."}, + {"ScanlineTimingWarning", u8"PPU timing has been changed."}, + {"ServerStarted", u8"Server started (Port: %1)"}, + {"ServerStopped", u8"Server stopped"}, + {"SoundRecorderStarted", u8"Recording to: %1"}, + {"SoundRecorderStopped", u8"Recording saved to: %1"}, + {"TestFileSavedTo", u8"Test file saved to: %1"}, + {"UnsupportedMapper", u8"Unsupported mapper (%1), cannot load game."}, + {"VideoRecorderStarted", u8"Recording to: %1"}, + {"VideoRecorderStopped", u8"Recording saved to: %1"}, }; std::list MessageManager::_log; @@ -93,7 +99,8 @@ void MessageManager::RegisterMessageManager(IMessageManager* messageManager) void MessageManager::UnregisterMessageManager(IMessageManager* messageManager) { auto lock = _messageLock.AcquireSafe(); - if(MessageManager::_messageManager == messageManager) { + if (MessageManager::_messageManager == messageManager) + { MessageManager::_messageManager = nullptr; } } @@ -105,7 +112,7 @@ void MessageManager::SetOsdState(bool enabled) string MessageManager::Localize(string key) { - std::unordered_map *resources = &_enResources; + std::unordered_map* resources = &_enResources; /*switch(EmulationSettings::GetDisplayLanguage()) { case Language::English: resources = &_enResources; break; case Language::French: resources = &_frResources; break; @@ -117,10 +124,12 @@ string MessageManager::Localize(string key) case Language::Catalan: resources = &_caResources; break; case Language::Chinese: resources = &_zhResources; break; }*/ - if(resources) { - if(resources->find(key) != resources->end()) { + if (resources) + { + if (resources->find(key) != resources->end()) + { return (*resources)[key]; - }/* else if(EmulationSettings::GetDisplayLanguage() != Language::English) { + } /* else if(EmulationSettings::GetDisplayLanguage() != Language::English) { //Fallback on English if resource key is missing another language resources = &_enResources; if(resources->find(key) != resources->end()) { @@ -134,9 +143,11 @@ string MessageManager::Localize(string key) void MessageManager::DisplayMessage(string title, string message, string param1, string param2) { - if(MessageManager::_messageManager) { + if (MessageManager::_messageManager) + { auto lock = _messageLock.AcquireSafe(); - if(!MessageManager::_messageManager) { + if (!MessageManager::_messageManager) + { return; } @@ -144,18 +155,23 @@ void MessageManager::DisplayMessage(string title, string message, string param1, message = Localize(message); size_t startPos = message.find(u8"%1"); - if(startPos != std::string::npos) { + if (startPos != std::string::npos) + { message.replace(startPos, 2, param1); } startPos = message.find(u8"%2"); - if(startPos != std::string::npos) { + if (startPos != std::string::npos) + { message.replace(startPos, 2, param2); } - if(_osdEnabled) { + if (_osdEnabled) + { MessageManager::_messageManager->DisplayMessage(title, message); - } else { + } + else + { MessageManager::Log("[" + title + "] " + message); } } @@ -165,10 +181,12 @@ void MessageManager::Log(string message) { #ifndef LIBRETRO auto lock = _logLock.AcquireSafe(); - if(message.empty()) { + if (message.empty()) + { message = "------------------------------------------------------"; } - if(_log.size() >= 1000) { + if (_log.size() >= 1000) + { _log.pop_front(); } _log.push_back(message); @@ -189,7 +207,8 @@ string MessageManager::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string &msg : _log) { + for (string& msg : _log) + { ss << msg << "\n"; } return ss.str(); diff --git a/Core/MessageManager.h b/Core/MessageManager.h index bbf14e1..a8b69b2 100644 --- a/Core/MessageManager.h +++ b/Core/MessageManager.h @@ -7,7 +7,7 @@ #include "../Utilities/SimpleLock.h" #ifdef _DEBUG - #define LogDebug(msg) MessageManager::Log(msg); +#define LogDebug(msg) MessageManager::Log(msg); #else #define LogDebug(msg) #endif @@ -22,7 +22,7 @@ private: static SimpleLock _logLock; static SimpleLock _messageLock; static std::list _log; - + public: static void SetOsdState(bool enabled); diff --git a/Core/MessageType.h b/Core/MessageType.h index c1318cc..7447485 100644 --- a/Core/MessageType.h +++ b/Core/MessageType.h @@ -12,4 +12,4 @@ enum class MessageType : uint8_t SelectController = 6, ForceDisconnect = 7, ServerInformation = 8 -}; \ No newline at end of file +}; diff --git a/Core/MovieDataMessage.h b/Core/MovieDataMessage.h index 3c22acd..2434652 100644 --- a/Core/MovieDataMessage.h +++ b/Core/MovieDataMessage.h @@ -10,14 +10,16 @@ private: ControlDeviceState _inputState; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_portNumber); s.StreamVector(_inputState.State); } public: - MovieDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + MovieDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } MovieDataMessage(ControlDeviceState state, uint8_t port) : NetMessage(MessageType::MovieData) { @@ -34,4 +36,4 @@ public: { return _inputState; } -}; \ No newline at end of file +}; diff --git a/Core/MovieManager.cpp b/Core/MovieManager.cpp index aecac96..55eb36a 100644 --- a/Core/MovieManager.cpp +++ b/Core/MovieManager.cpp @@ -15,7 +15,8 @@ MovieManager::MovieManager(shared_ptr console) void MovieManager::Record(RecordMovieOptions options) { shared_ptr recorder(new MovieRecorder(_console)); - if(recorder->Record(options)) { + if (recorder->Record(options)) + { _recorder = recorder; } } @@ -23,22 +24,27 @@ void MovieManager::Record(RecordMovieOptions options) void MovieManager::Play(VirtualFile file, bool forTest) { vector fileData; - if(file.IsValid() && file.ReadFile(fileData)) { + if (file.IsValid() && file.ReadFile(fileData)) + { shared_ptr player; - if(memcmp(fileData.data(), "PK", 2) == 0) { + if (memcmp(fileData.data(), "PK", 2) == 0) + { //Mesen movie ZipReader reader; reader.LoadArchive(fileData); vector files = reader.GetFileList(); - if(std::find(files.begin(), files.end(), "GameSettings.txt") != files.end()) { + if (std::find(files.begin(), files.end(), "GameSettings.txt") != files.end()) + { player.reset(new MesenMovie(_console, forTest)); } } - if(player && player->Play(file)) { + if (player && player->Play(file)) + { _player = player; - if(!forTest) { + if (!forTest) + { MessageManager::DisplayMessage("Movies", "MoviePlaying", file.GetFileName()); } } diff --git a/Core/MovieManager.h b/Core/MovieManager.h index 9d4b2a5..12d6171 100644 --- a/Core/MovieManager.h +++ b/Core/MovieManager.h @@ -11,7 +11,7 @@ class Console; class IMovie : public IInputProvider { public: - virtual bool Play(VirtualFile &file) = 0; + virtual bool Play(VirtualFile& file) = 0; virtual bool IsPlaying() = 0; }; @@ -30,4 +30,4 @@ public: void Stop(); bool Playing(); bool Recording(); -}; \ No newline at end of file +}; diff --git a/Core/MovieRecorder.cpp b/Core/MovieRecorder.cpp index 4c4a0da..ef82ad6 100644 --- a/Core/MovieRecorder.cpp +++ b/Core/MovieRecorder.cpp @@ -38,29 +38,37 @@ bool MovieRecorder::Record(RecordMovieOptions options) _saveStateData = stringstream(); _hasSaveState = false; - if(!_writer->Initialize(_filename)) { + if (!_writer->Initialize(_filename)) + { MessageManager::DisplayMessage("Movies", "CouldNotWriteToFile", FolderUtilities::GetFilename(_filename, true)); _writer.reset(); return false; - } else { + } + else + { _console->Lock(); _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); - if(options.RecordFrom == RecordMovieFrom::StartWithoutSaveData) { + if (options.RecordFrom == RecordMovieFrom::StartWithoutSaveData) + { //Power cycle and ignore save data that exists on the disk _console->GetBatteryManager()->SetBatteryProvider(shared_from_this()); _console->PowerCycle(); - } else if(options.RecordFrom == RecordMovieFrom::StartWithSaveData) { + } + else if (options.RecordFrom == RecordMovieFrom::StartWithSaveData) + { //Power cycle and save existing battery files into the movie file _console->GetBatteryManager()->SetBatteryRecorder(shared_from_this()); _console->PowerCycle(); - } else if(options.RecordFrom == RecordMovieFrom::CurrentState) { + } + else if (options.RecordFrom == RecordMovieFrom::CurrentState) + { //Record from current state, store a save state in the movie file _console->GetControlManager()->RegisterInputRecorder(this); _console->GetSaveStateManager()->SaveState(_saveStateData); _hasSaveState = true; } - + _console->GetBatteryManager()->SetBatteryRecorder(nullptr); _console->Unlock(); @@ -70,12 +78,12 @@ bool MovieRecorder::Record(RecordMovieOptions options) } } -void MovieRecorder::GetGameSettings(stringstream &out) +void MovieRecorder::GetGameSettings(stringstream& out) { EmuSettings* settings = _console->GetSettings().get(); EmulationConfig emuConfig = settings->GetEmulationConfig(); InputConfig inputConfig = settings->GetInputConfig(); - + WriteString(out, MovieKeys::MesenVersion, settings->GetVersionString()); WriteInt(out, MovieKeys::MovieFormatVersion, MovieRecorder::MovieFormatVersion); @@ -84,20 +92,24 @@ void MovieRecorder::GetGameSettings(stringstream &out) WriteString(out, MovieKeys::Sha1, _console->GetCartridge()->GetSha1Hash()); VirtualFile patchFile = _console->GetRomInfo().PatchFile; - if(patchFile.IsValid()) { + if (patchFile.IsValid()) + { WriteString(out, MovieKeys::PatchFile, patchFile.GetFileName()); WriteString(out, MovieKeys::PatchFileSha1, patchFile.GetSha1Hash()); - + romFile.ApplyPatch(patchFile); WriteString(out, MovieKeys::PatchedRomSha1, romFile.GetSha1Hash()); } ConsoleRegion region = _console->GetRegion(); - switch(region) { - case ConsoleRegion::Auto: - case ConsoleRegion::Ntsc: WriteString(out, MovieKeys::Region, "NTSC"); break; + switch (region) + { + case ConsoleRegion::Auto: + case ConsoleRegion::Ntsc: WriteString(out, MovieKeys::Region, "NTSC"); + break; - case ConsoleRegion::Pal: WriteString(out, MovieKeys::Region, "PAL"); break; + case ConsoleRegion::Pal: WriteString(out, MovieKeys::Region, "PAL"); + break; } WriteString(out, MovieKeys::Controller1, ControllerTypeNames[(int)inputConfig.Controllers[0].Type]); @@ -109,36 +121,42 @@ void MovieRecorder::GetGameSettings(stringstream &out) WriteInt(out, MovieKeys::ExtraScanlinesBeforeNmi, emuConfig.PpuExtraScanlinesBeforeNmi); WriteInt(out, MovieKeys::ExtraScanlinesAfterNmi, emuConfig.PpuExtraScanlinesAfterNmi); WriteInt(out, MovieKeys::GsuClockSpeed, emuConfig.GsuClockSpeed); - - switch(emuConfig.RamPowerOnState) { - case RamState::AllZeros: WriteString(out, MovieKeys::RamPowerOnState, "AllZeros"); break; - case RamState::AllOnes: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); break; - case RamState::Random: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); break; //TODO: Random memory isn't supported for movies yet + + switch (emuConfig.RamPowerOnState) + { + case RamState::AllZeros: WriteString(out, MovieKeys::RamPowerOnState, "AllZeros"); + break; + case RamState::AllOnes: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); + break; + case RamState::Random: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); + break; //TODO: Random memory isn't supported for movies yet } - for(CheatCode &code : _console->GetCheatManager()->GetCheats()) { + for (CheatCode& code : _console->GetCheatManager()->GetCheats()) + { out << "Cheat " << HexUtilities::ToHex24(code.Address) << " " << HexUtilities::ToHex(code.Value) << "\n"; } } -void MovieRecorder::WriteString(stringstream &out, string name, string value) +void MovieRecorder::WriteString(stringstream& out, string name, string value) { out << name << " " << value << "\n"; } -void MovieRecorder::WriteInt(stringstream &out, string name, uint32_t value) +void MovieRecorder::WriteInt(stringstream& out, string name, uint32_t value) { out << name << " " << std::to_string(value) << "\n"; } -void MovieRecorder::WriteBool(stringstream &out, string name, bool enabled) +void MovieRecorder::WriteBool(stringstream& out, string name, bool enabled) { out << name << " " << (enabled ? "true" : "false") << "\n"; } bool MovieRecorder::Stop() { - if(_writer) { + if (_writer) + { _console->GetControlManager()->UnregisterInputRecorder(this); _writer->AddFile(_inputData, "Input.txt"); @@ -147,7 +165,8 @@ bool MovieRecorder::Stop() GetGameSettings(out); _writer->AddFile(out, "GameSettings.txt"); - if(!_author.empty() || !_description.empty()) { + if (!_author.empty() || !_description.empty()) + { stringstream movieInfo; WriteString(movieInfo, "Author", _author); movieInfo << "Description\n" << _description; @@ -156,20 +175,24 @@ bool MovieRecorder::Stop() VirtualFile patchFile = _console->GetRomInfo().PatchFile; vector patchData; - if(patchFile.IsValid() && patchFile.ReadFile(patchData)) { + if (patchFile.IsValid() && patchFile.ReadFile(patchData)) + { _writer->AddFile(patchData, "PatchData.dat"); } - if(_hasSaveState) { + if (_hasSaveState) + { _writer->AddFile(_saveStateData, "SaveState.mss"); } - for(auto kvp : _batteryData) { + for (auto kvp : _batteryData) + { _writer->AddFile(kvp.second, "Battery" + kvp.first); } bool result = _writer->Save(); - if(result) { + if (result) + { MessageManager::DisplayMessage("Movies", "MovieSaved", FolderUtilities::GetFilename(_filename, true)); } return result; @@ -178,30 +201,36 @@ bool MovieRecorder::Stop() return false; } -bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, uint32_t startPosition, uint32_t endPosition) +bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, uint32_t startPosition, + uint32_t endPosition) { _filename = movieFile; _writer.reset(new ZipWriter()); - if (startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) { + if (startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) + { vector> devices = _console->GetControlManager()->GetControlDevices(); -// if (startPosition > 0 || _console->GetRomInfo().Header.SramSize || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) { // TODO? - //Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random) - _hasSaveState = true; - _saveStateData = stringstream(); - _console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData); - data[startPosition].GetStateData(_saveStateData); -// } + // if (startPosition > 0 || _console->GetRomInfo().Header.SramSize || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) { // TODO? + //Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random) + _hasSaveState = true; + _saveStateData = stringstream(); + _console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData); + data[startPosition].GetStateData(_saveStateData); + // } _inputData = stringstream(); - for (uint32_t i = startPosition; i < endPosition; i++) { + for (uint32_t i = startPosition; i < endPosition; i++) + { RewindData rewindData = data[i]; - for (uint32_t i = 0; i < 60; i++) { - for (shared_ptr& device : devices) { + for (uint32_t i = 0; i < 60; i++) + { + for (shared_ptr& device : devices) + { uint8_t port = device->GetPort(); - if (i < rewindData.InputLogs[port].size()) { + if (i < rewindData.InputLogs[port].size()) + { device->SetRawState(rewindData.InputLogs[port][i]); _inputData << ("|" + device->GetTextState()); } @@ -219,7 +248,8 @@ bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, void MovieRecorder::RecordInput(vector> devices) { - for(shared_ptr &device : devices) { + for (shared_ptr& device : devices) + { _inputData << ("|" + device->GetTextState()); } _inputData << "\n"; @@ -235,9 +265,10 @@ vector MovieRecorder::LoadBattery(string extension) return vector(); } -void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void *parameter) +void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded) { + if (type == ConsoleNotificationType::GameLoaded) + { _console->GetControlManager()->RegisterInputRecorder(this); } } diff --git a/Core/MovieRecorder.h b/Core/MovieRecorder.h index b2ec281..8767565 100644 --- a/Core/MovieRecorder.h +++ b/Core/MovieRecorder.h @@ -12,7 +12,8 @@ class Console; class RewindData; //struct CodeInfo; -class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this +class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, + public IBatteryProvider, public std::enable_shared_from_this { private: static const uint32_t MovieFormatVersion = 1; @@ -27,11 +28,11 @@ private: bool _hasSaveState = false; stringstream _saveStateData; - void GetGameSettings(stringstream &out); + void GetGameSettings(stringstream& out); //void WriteCheat(stringstream &out, CodeInfo &code); - void WriteString(stringstream &out, string name, string value); - void WriteInt(stringstream &out, string name, uint32_t value); - void WriteBool(stringstream &out, string name, bool enabled); + void WriteString(stringstream& out, string name, string value); + void WriteInt(stringstream& out, string name, uint32_t value); + void WriteBool(stringstream& out, string name, bool enabled); public: MovieRecorder(shared_ptr console); @@ -50,5 +51,5 @@ public: vector LoadBattery(string extension) override; // Inherited via INotificationListener - void ProcessNotification(ConsoleNotificationType type, void *parameter) override; + void ProcessNotification(ConsoleNotificationType type, void* parameter) override; }; diff --git a/Core/MovieTypes.h b/Core/MovieTypes.h index 7c324a6..9564c8a 100644 --- a/Core/MovieTypes.h +++ b/Core/MovieTypes.h @@ -58,4 +58,4 @@ namespace MovieKeys constexpr const char* RamPowerOnState = "RamPowerOnState"; constexpr const char* InputPollScanline = "InputPollScanline"; constexpr const char* GsuClockSpeed = "GsuClockSpeed"; -}; \ No newline at end of file +}; diff --git a/Core/Msu1.cpp b/Core/Msu1.cpp index e969bec..cea1ee0 100644 --- a/Core/Msu1.cpp +++ b/Core/Msu1.cpp @@ -8,11 +8,16 @@ Msu1* Msu1::Init(VirtualFile romFile, Spc* spc) { string romFolder = romFile.GetFolderPath(); string romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); - if(ifstream(FolderUtilities::CombinePath(romFolder, romName + ".msu"))) { + if (ifstream(FolderUtilities::CombinePath(romFolder, romName + ".msu"))) + { return new Msu1(romFile, spc); - } else if(ifstream(FolderUtilities::CombinePath(romFolder, "msu1.rom"))) { + } + else if (ifstream(FolderUtilities::CombinePath(romFolder, "msu1.rom"))) + { return new Msu1(romFile, spc); - } else { + } + else + { return nullptr; } } @@ -23,71 +28,86 @@ Msu1::Msu1(VirtualFile romFile, Spc* spc) _romFolder = romFile.GetFolderPath(); _romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); _dataFile.open(FolderUtilities::CombinePath(_romFolder, _romName) + ".msu", ios::binary); - if(_dataFile) { + if (_dataFile) + { _trackPath = FolderUtilities::CombinePath(_romFolder, _romName); - } else { + } + else + { _dataFile.open(FolderUtilities::CombinePath(_romFolder, "msu1.rom"), ios::binary); _trackPath = FolderUtilities::CombinePath(_romFolder, "track"); } - if(_dataFile) { + if (_dataFile) + { _dataFile.seekg(0, ios::end); _dataSize = (uint32_t)_dataFile.tellg(); - } else { + } + else + { _dataSize = 0; } } void Msu1::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2000: _tmpDataPointer = (_tmpDataPointer & 0xFFFFFF00) | value; break; - case 0x2001: _tmpDataPointer = (_tmpDataPointer & 0xFFFF00FF) | (value << 8); break; - case 0x2002: _tmpDataPointer = (_tmpDataPointer & 0xFF00FFFF) | (value << 16); break; - case 0x2003: - _tmpDataPointer = (_tmpDataPointer & 0x00FFFFFF) | (value << 24); - _dataPointer = _tmpDataPointer; - _dataFile.seekg(_dataPointer, ios::beg); - break; + switch (addr) + { + case 0x2000: _tmpDataPointer = (_tmpDataPointer & 0xFFFFFF00) | value; + break; + case 0x2001: _tmpDataPointer = (_tmpDataPointer & 0xFFFF00FF) | (value << 8); + break; + case 0x2002: _tmpDataPointer = (_tmpDataPointer & 0xFF00FFFF) | (value << 16); + break; + case 0x2003: + _tmpDataPointer = (_tmpDataPointer & 0x00FFFFFF) | (value << 24); + _dataPointer = _tmpDataPointer; + _dataFile.seekg(_dataPointer, ios::beg); + break; - case 0x2004: _trackSelect = (_trackSelect & 0xFF00) | value; break; - case 0x2005: - _trackSelect = (_trackSelect & 0xFF) | (value << 8); - LoadTrack(); - break; + case 0x2004: _trackSelect = (_trackSelect & 0xFF00) | value; + break; + case 0x2005: + _trackSelect = (_trackSelect & 0xFF) | (value << 8); + LoadTrack(); + break; - case 0x2006: _volume = value; break; - case 0x2007: - if(!_audioBusy) { - _repeat = (value & 0x02) != 0; - _paused = (value & 0x01) == 0; - _pcmReader.SetLoopFlag(_repeat); - } - break; + case 0x2006: _volume = value; + break; + case 0x2007: + if (!_audioBusy) + { + _repeat = (value & 0x02) != 0; + _paused = (value & 0x01) == 0; + _pcmReader.SetLoopFlag(_repeat); + } + break; } } uint8_t Msu1::Read(uint16_t addr) { - switch(addr) { - case 0x2000: - //status - return (_dataBusy << 7) | (_audioBusy << 6) | (_repeat << 5) | ((!_paused) << 4) | (_trackMissing << 3) | 0x01; + switch (addr) + { + case 0x2000: + //status + return (_dataBusy << 7) | (_audioBusy << 6) | (_repeat << 5) | ((!_paused) << 4) | (_trackMissing << 3) | 0x01; - case 0x2001: - //data - if(!_dataBusy && _dataPointer < _dataSize) { - _dataPointer++; - return (uint8_t)_dataFile.get(); - } - return 0; + case 0x2001: + //data + if (!_dataBusy && _dataPointer < _dataSize) + { + _dataPointer++; + return (uint8_t)_dataFile.get(); + } + return 0; - case 0x2002: return 'S'; - case 0x2003: return '-'; - case 0x2004: return 'M'; - case 0x2005: return 'S'; - case 0x2006: return 'U'; - case 0x2007: return '1'; + case 0x2002: return 'S'; + case 0x2003: return '-'; + case 0x2004: return 'M'; + case 0x2005: return 'S'; + case 0x2006: return 'U'; + case 0x2007: return '1'; } return 0; @@ -95,7 +115,8 @@ uint8_t Msu1::Read(uint16_t addr) void Msu1::MixAudio(int16_t* buffer, size_t sampleCount, uint32_t sampleRate) { - if(!_paused) { + if (!_paused) + { _pcmReader.SetSampleRate(sampleRate); _pcmReader.ApplySamples(buffer, sampleCount, _spc->IsMuted() ? 0 : _volume); } @@ -106,11 +127,13 @@ void Msu1::LoadTrack(uint32_t startOffset) _trackMissing = !_pcmReader.Init(_trackPath + "-" + std::to_string(_trackSelect) + ".pcm", _repeat, startOffset); } -void Msu1::Serialize(Serializer &s) +void Msu1::Serialize(Serializer& s) { uint32_t offset = _pcmReader.GetOffset(); - s.Stream(_trackSelect, _tmpDataPointer, _dataPointer, _repeat, _paused, _volume, _trackMissing, _audioBusy, _dataBusy, offset); - if(!s.IsSaving()) { + s.Stream(_trackSelect, _tmpDataPointer, _dataPointer, _repeat, _paused, _volume, _trackMissing, _audioBusy, + _dataBusy, offset); + if (!s.IsSaving()) + { _dataFile.seekg(_dataPointer, ios::beg); LoadTrack(offset); } diff --git a/Core/Msu1.h b/Core/Msu1.h index 85cbab0..2a7f805 100644 --- a/Core/Msu1.h +++ b/Core/Msu1.h @@ -9,7 +9,7 @@ class Spc; class Msu1 final : public ISerializable { private: - Spc * _spc; + Spc* _spc; PcmReader _pcmReader; uint8_t _volume = 100; uint16_t _trackSelect = 0; @@ -27,18 +27,18 @@ private: ifstream _dataFile; uint32_t _dataSize; - + void LoadTrack(uint32_t startOffset = 8); public: Msu1(VirtualFile romFile, Spc* spc); - + static Msu1* Init(VirtualFile romFile, Spc* spc); void Write(uint16_t addr, uint8_t value); uint8_t Read(uint16_t addr); - - void MixAudio(int16_t *buffer, size_t sampleCount, uint32_t sampleRate); - - void Serialize(Serializer &s); -}; \ No newline at end of file + + void MixAudio(int16_t* buffer, size_t sampleCount, uint32_t sampleRate); + + void Serialize(Serializer& s); +}; diff --git a/Core/Multitap.cpp b/Core/Multitap.cpp index 5f1b8df..682a4f6 100644 --- a/Core/Multitap.cpp +++ b/Core/Multitap.cpp @@ -11,9 +11,11 @@ string Multitap::GetKeyNames() void Multitap::InternalSetStateFromInput() { - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { int offset = Multitap::ButtonCount * i; - for(KeyMapping keyMapping : _mappings[i]) { + for (KeyMapping keyMapping : _mappings[i]) + { SetPressedState(Buttons::A + offset, keyMapping.A); SetPressedState(Buttons::B + offset, keyMapping.B); SetPressedState(Buttons::X + offset, keyMapping.X); @@ -29,7 +31,8 @@ void Multitap::InternalSetStateFromInput() uint8_t turboFreq = 1 << (4 - _turboSpeed[i]); bool turboOn = (uint8_t)(_console->GetFrameCount() % turboFreq) < turboFreq / 2; - if(turboOn) { + if (turboOn) + { SetPressedState(Buttons::A + offset, keyMapping.TurboA); SetPressedState(Buttons::B + offset, keyMapping.TurboB); SetPressedState(Buttons::X + offset, keyMapping.TurboX); @@ -41,7 +44,7 @@ void Multitap::InternalSetStateFromInput() } } -void Multitap::UpdateControllerState(uint8_t controllerNumber, SnesController &controller) +void Multitap::UpdateControllerState(uint8_t controllerNumber, SnesController& controller) { int offset = Multitap::ButtonCount * controllerNumber; SetBitValue(Buttons::A + offset, controller.IsPressed(Buttons::A)); @@ -79,7 +82,7 @@ uint16_t Multitap::ToByte(uint8_t port) ((uint8_t)IsPressed(Buttons::R + offset) << 11); } -void Multitap::Serialize(Serializer & s) +void Multitap::Serialize(Serializer& s) { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer[0], _stateBuffer[1], _stateBuffer[2], _stateBuffer[3]); @@ -87,12 +90,15 @@ void Multitap::Serialize(Serializer & s) void Multitap::RefreshStateBuffer() { - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _stateBuffer[i] = ToByte(i); } } -Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console, port, keyMappings1) +Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, + KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice( + console, port, keyMappings1) { _turboSpeed[0] = keyMappings1.TurboSpeed; _turboSpeed[1] = keyMappings2.TurboSpeed; @@ -124,13 +130,15 @@ uint8_t Multitap::ReadRam(uint16_t addr) uint8_t portSelect = (_internalRegs->GetIoPortOutput() & selectBit) ? 0 : 2; uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); output = _stateBuffer[portSelect] & 0x01; - output |= (_stateBuffer[portSelect + 1] & 0x01) << 1; //P3 & P5 are reported in bit 1 + output |= (_stateBuffer[portSelect + 1] & 0x01) << 1; //P3 & P5 are reported in bit 1 - if(_strobe) { + if (_strobe) + { //Bit 1 is always set when strobe is high output |= 0x02; } @@ -148,7 +156,8 @@ uint8_t Multitap::ReadRam(uint16_t addr) void Multitap::WriteRam(uint16_t addr, uint8_t value) { - if(addr == 0x4016) { + if (addr == 0x4016) + { StrobeProcessWrite(value); } } diff --git a/Core/Multitap.h b/Core/Multitap.h index e84b8c8..b9979cd 100644 --- a/Core/Multitap.h +++ b/Core/Multitap.h @@ -10,23 +10,25 @@ class Multitap : public BaseControlDevice { private: enum Buttons { A = 0, B, X, Y, L, R, Select, Start, Up, Down, Left, Right }; + static constexpr int ButtonCount = 12; vector _mappings[4]; uint8_t _turboSpeed[4] = {}; uint16_t _stateBuffer[4] = {}; - InternalRegisters *_internalRegs = nullptr; + InternalRegisters* _internalRegs = nullptr; protected: string GetKeyNames() override; void InternalSetStateFromInput() override; - void UpdateControllerState(uint8_t controllerNumber, SnesController &controller); + void UpdateControllerState(uint8_t controllerNumber, SnesController& controller); uint16_t ToByte(uint8_t port); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void RefreshStateBuffer() override; public: - Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4); + Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, + KeyMappingSet keyMappings3, KeyMappingSet keyMappings4); ControllerType GetControllerType() override; @@ -34,4 +36,4 @@ public: uint8_t ReadRam(uint16_t addr) override; void WriteRam(uint16_t addr, uint8_t value) override; -}; \ No newline at end of file +}; diff --git a/Core/NecDsp.cpp b/Core/NecDsp.cpp index 49b750c..691fb94 100644 --- a/Core/NecDsp.cpp +++ b/Core/NecDsp.cpp @@ -13,18 +13,23 @@ #include "FirmwareHelper.h" #include "../Utilities/FolderUtilities.h" -NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programRom, vector &dataRom) : BaseCoprocessor(SnesMemoryType::Register) +NecDsp::NecDsp(CoprocessorType type, Console* console, vector& programRom, + vector& dataRom) : BaseCoprocessor(SnesMemoryType::Register) { _console = console; _type = type; _memoryManager = console->GetMemoryManager().get(); _memoryType = SnesMemoryType::Register; - MemoryMappings *mm = _memoryManager->GetMemoryMappings(); - - if(type == CoprocessorType::ST010 || type == CoprocessorType::ST011) { - if(type == CoprocessorType::ST010) { + MemoryMappings* mm = _memoryManager->GetMemoryMappings(); + + if (type == CoprocessorType::ST010 || type == CoprocessorType::ST011) + { + if (type == CoprocessorType::ST010) + { _frequency = 11000000; - } else { + } + else + { _frequency = 22000000; } _registerMask = 0x0001; @@ -34,11 +39,14 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR mm->RegisterHandler(0xE0, 0xE0, 0x0000, 0x0FFF, this); mm->RegisterHandler(0x68, 0x6F, 0x0000, 0x0FFF, this); mm->RegisterHandler(0xE8, 0xEF, 0x0000, 0x0FFF, this); - } else { + } + else + { _ramSize = 0x100; _stackSize = 4; _frequency = 7600000; - if(console->GetCartridge()->GetCartFlags() & CartFlags::LoRom) { + if (console->GetCartridge()->GetCartFlags() & CartFlags::LoRom) + { _registerMask = 0x4000; mm->RegisterHandler(0x30, 0x3F, 0x8000, 0xFFFF, this); mm->RegisterHandler(0xB0, 0xBF, 0x8000, 0xFFFF, this); @@ -46,7 +54,9 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR //For Super Bases Loaded 2 mm->RegisterHandler(0x60, 0x6F, 0x0000, 0x7FFF, this); mm->RegisterHandler(0xE0, 0xEF, 0x0000, 0x7FFF, this); - } else if(console->GetCartridge()->GetCartFlags() & CartFlags::HiRom) { + } + else if (console->GetCartridge()->GetCartFlags() & CartFlags::HiRom) + { _registerMask = 0x1000; mm->RegisterHandler(0x00, 0x1F, 0x6000, 0x7FFF, this); mm->RegisterHandler(0x80, 0x9F, 0x6000, 0x7FFF, this); @@ -56,7 +66,7 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR _progSize = (uint32_t)programRom.size(); _progRom = new uint8_t[_progSize]; _prgCache = new uint32_t[_progSize / 3]; - _progMask = (_progSize / 3)- 1; + _progMask = (_progSize / 3) - 1; _dataSize = (uint32_t)dataRom.size() / 2; _dataRom = new uint16_t[_dataSize]; @@ -73,7 +83,8 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR memcpy(_progRom, programRom.data(), _progSize); BuildProgramCache(); - for(uint32_t i = 0; i < _dataSize; i++) { + for (uint32_t i = 0; i < _dataSize; i++) + { _dataRom[i] = dataRom[i * 2] | (dataRom[i * 2 + 1] << 8); } } @@ -86,23 +97,46 @@ NecDsp::~NecDsp() delete[] _ram; } -NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console *console, vector &embeddedFirware) +NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console* console, vector& embeddedFirware) { bool firmwareLoaded = false; vector programRom; vector dataRom; - switch(type) { - case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1B, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP2, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP3, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP4, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST010, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break; - case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST011, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break; - default: break; + switch (type) + { + case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP1, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP1B, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP2, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP3, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP4, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::ST010, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, + embeddedFirware, 0xC000, 0x1000); + break; + case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::ST011, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, + embeddedFirware, 0xC000, 0x1000); + break; + default: break; } - if(!firmwareLoaded) { + if (!firmwareLoaded) + { return nullptr; } @@ -117,14 +151,16 @@ void NecDsp::Reset() void NecDsp::LoadBattery() { - if(_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) { + if (_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) + { _console->GetBatteryManager()->LoadBattery(".srm", (uint8_t*)_ram, _ramSize * sizeof(uint16_t)); } } void NecDsp::SaveBattery() { - if(_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) { + if (_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) + { _console->GetBatteryManager()->SaveBattery(".srm", (uint8_t*)_ram, _ramSize * sizeof(uint16_t)); } } @@ -132,7 +168,8 @@ void NecDsp::SaveBattery() void NecDsp::BuildProgramCache() { //For the sake of performance, keep a precalculated array of 24-bit opcodes for each entry in the ROM - for(uint32_t i = 0; i < _progSize / 3; i++) { + for (uint32_t i = 0; i < _progSize / 3; i++) + { _prgCache[i] = _progRom[i * 3] | (_progRom[i * 3 + 1] << 8) | (_progRom[i * 3 + 2] << 16); } } @@ -147,20 +184,27 @@ void NecDsp::Run() { uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * (_frequency / _console->GetMasterClockRate())); - if(_inRqmLoop && !_console->IsDebugging()) { + if (_inRqmLoop && !_console->IsDebugging()) + { _cycleCount = targetCycle; return; } - while(_cycleCount < targetCycle) { + while (_cycleCount < targetCycle) + { ReadOpCode(); _state.PC++; - switch(_opCode & 0xC00000) { - case 0x000000: ExecOp(); break; - case 0x400000: ExecAndReturn(); break; - case 0x800000: Jump(); break; - case 0xC00000: Load(_opCode & 0x0F, (uint16_t)(_opCode >> 6)); break; + switch (_opCode & 0xC00000) + { + case 0x000000: ExecOp(); + break; + case 0x400000: ExecAndReturn(); + break; + case 0x800000: Jump(); + break; + case 0xC00000: Load(_opCode & 0x0F, (uint16_t)(_opCode >> 6)); + break; } //Store the multiplication's result @@ -176,28 +220,39 @@ uint8_t NecDsp::Read(uint32_t addr) { Run(); - if((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) { + if ((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) + { //RAM (Banks $68-$6F) uint16_t value = _ram[(addr >> 1) & _ramMask]; return (addr & 0x01) ? (uint8_t)(value >> 8) : (uint8_t)value; - } else if(addr & _registerMask) { + } + else if (addr & _registerMask) + { //SR return (_state.SR >> 8); - } else { + } + else + { //DR _inRqmLoop = false; - if(_state.SR & NecDspStatusFlags::DataRegControl) { + if (_state.SR & NecDspStatusFlags::DataRegControl) + { //8 bits _state.SR &= ~NecDspStatusFlags::RequestForMaster; return (uint8_t)_state.DR; - } else { + } + else + { //16 bits - if(_state.SR & NecDspStatusFlags::DataRegStatus) { + if (_state.SR & NecDspStatusFlags::DataRegStatus) + { _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.SR &= ~NecDspStatusFlags::DataRegStatus; return _state.DR >> 8; - } else { + } + else + { _state.SR |= NecDspStatusFlags::DataRegStatus; return (uint8_t)_state.DR; } @@ -209,29 +264,41 @@ void NecDsp::Write(uint32_t addr, uint8_t value) { Run(); - if((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) { + if ((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) + { //RAM (Banks $68-$6F) uint16_t ramAddr = (addr >> 1) & _ramMask; - if(addr & 0x01) { + if (addr & 0x01) + { _ram[ramAddr] = (_ram[ramAddr] & 0xFF) | (value << 8); - } else { + } + else + { _ram[ramAddr] = (_ram[ramAddr] & 0xFF00) | value; } - } else if(!(addr & _registerMask)) { + } + else if (!(addr & _registerMask)) + { //DR _inRqmLoop = false; - if(_state.SR & NecDspStatusFlags::DataRegControl) { + if (_state.SR & NecDspStatusFlags::DataRegControl) + { //8 bits _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.DR = (_state.DR & 0xFF00) | value; - } else { + } + else + { //16 bits - if(_state.SR & NecDspStatusFlags::DataRegStatus) { + if (_state.SR & NecDspStatusFlags::DataRegStatus) + { _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.SR &= ~NecDspStatusFlags::DataRegStatus; _state.DR = (_state.DR & 0xFF) | (value << 8); - } else { + } + else + { _state.SR |= NecDspStatusFlags::DataRegStatus; _state.DR = (_state.DR & 0xFF00) | value; } @@ -245,14 +312,14 @@ uint8_t NecDsp::Peek(uint32_t addr) return 0; } -void NecDsp::PeekBlock(uint32_t addr, uint8_t *output) +void NecDsp::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo NecDsp::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) @@ -268,78 +335,121 @@ void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) //Select the 2nd operand for the operation uint8_t pSelect = (_opCode >> 20) & 0x03; uint16_t p; - switch(pSelect) { - case 0: p = _ram[_state.DP & _ramMask]; break; - case 1: p = source; break; - case 2: p = _state.M; break; - case 3: p = _state.N; break; + switch (pSelect) + { + case 0: p = _ram[_state.DP & _ramMask]; + break; + case 1: p = source; + break; + case 2: p = _state.M; + break; + case 3: p = _state.N; + break; } //Perform the ALU operation, and set flags - switch(aluOperation) { - case 0x00: break; - case 0x01: result = acc | p; break; - case 0x02: result = acc & p; break; - case 0x03: result = acc ^ p; break; - case 0x04: result = acc - p; break; - case 0x05: result = acc + p; break; - case 0x06: result = acc - p - otherCarry; break; - case 0x07: result = acc + p + otherCarry; break; - case 0x08: result = acc - 1; p = 1; break; - case 0x09: result = acc + 1; p = 1; break; + switch (aluOperation) + { + case 0x00: break; + case 0x01: result = acc | p; + break; + case 0x02: result = acc & p; + break; + case 0x03: result = acc ^ p; + break; + case 0x04: result = acc - p; + break; + case 0x05: result = acc + p; + break; + case 0x06: result = acc - p - otherCarry; + break; + case 0x07: result = acc + p + otherCarry; + break; + case 0x08: result = acc - 1; + p = 1; + break; + case 0x09: result = acc + 1; + p = 1; + break; - case 0x0A: result = ~acc; break; - case 0x0B: result = (acc >> 1) | (acc & 0x8000); break; - case 0x0C: result = (acc << 1) | (uint8_t)otherCarry; break; - case 0x0D: result = (acc << 2) | 0x03; break; - case 0x0E: result = (acc << 4) | 0x0F; break; - case 0x0F: result = (acc << 8) | (acc >> 8); break; + case 0x0A: result = ~acc; + break; + case 0x0B: result = (acc >> 1) | (acc & 0x8000); + break; + case 0x0C: result = (acc << 1) | (uint8_t)otherCarry; + break; + case 0x0D: result = (acc << 2) | 0x03; + break; + case 0x0E: result = (acc << 4) | 0x0F; + break; + case 0x0F: result = (acc << 8) | (acc >> 8); + break; } flags.Zero = result == 0; flags.Sign0 = (result & 0x8000) >> 15; - if(!flags.Overflow1) { + if (!flags.Overflow1) + { flags.Sign1 = flags.Sign0; } - switch(aluOperation) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x0A: case 0x0D: case 0x0E: case 0x0F: - flags.Carry = false; - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + switch (aluOperation) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x0A: + case 0x0D: + case 0x0E: + case 0x0F: + flags.Carry = false; + flags.Overflow0 = false; + flags.Overflow1 = false; + break; - case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + { uint16_t overflow = (acc ^ result) & (p ^ ((aluOperation & 0x01) ? result : acc)); flags.Overflow0 = (bool)((overflow & 0x8000) >> 15); - if(flags.Overflow0 && flags.Overflow1) { + if (flags.Overflow0 && flags.Overflow1) + { flags.Overflow1 = flags.Sign0 == flags.Sign1; - } else { + } + else + { flags.Overflow1 |= flags.Overflow0; } flags.Carry = (bool)(((acc ^ p ^ result ^ overflow) & 0x8000) >> 15); break; } - case 0x0B: - flags.Carry = (bool)(acc & 0x01); - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + case 0x0B: + flags.Carry = (bool)(acc & 0x01); + flags.Overflow0 = false; + flags.Overflow1 = false; + break; - case 0x0C: - flags.Carry = (bool)((acc >> 15) & 0x01); - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + case 0x0C: + flags.Carry = (bool)((acc >> 15) & 0x01); + flags.Overflow0 = false; + flags.Overflow1 = false; + break; } //Update selected accumulator/flags with the operation's results - if(accSelect) { + if (accSelect) + { _state.B = result; _state.FlagsB = flags; - } else { + } + else + { _state.A = result; _state.FlagsA = flags; } @@ -348,11 +458,15 @@ void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) void NecDsp::UpdateDataPointer() { uint16_t dp = _state.DP; - switch((_opCode >> 13) & 0x03) { - case 0: break; //NOP - case 1: dp = (dp & 0xF0) | ((dp + 1) & 0x0F); break; //Increment lower nibble, with no carry - case 2: dp = (dp & 0xF0) | ((dp - 1) & 0x0F); break; //Decrement lower nibble, with no carry - case 3: dp &= 0xF0; break; //Clear lower nibble + switch ((_opCode >> 13) & 0x03) + { + case 0: break; //NOP + case 1: dp = (dp & 0xF0) | ((dp + 1) & 0x0F); + break; //Increment lower nibble, with no carry + case 2: dp = (dp & 0xF0) | ((dp - 1) & 0x0F); + break; //Decrement lower nibble, with no carry + case 3: dp &= 0xF0; + break; //Clear lower nibble } uint8_t dpHighModify = (_opCode >> 9) & 0x0F; @@ -365,7 +479,8 @@ void NecDsp::ExecOp() uint16_t source = GetSourceValue((_opCode >> 4) & 0x0F); //First, process the ALU operation, if needed - if(aluOperation) { + if (aluOperation) + { RunApuOp(aluOperation, source); } @@ -373,13 +488,15 @@ void NecDsp::ExecOp() uint8_t dest = _opCode & 0x0F; Load(dest, source); - if(dest != 0x04) { + if (dest != 0x04) + { //Destination was not the data pointer (DP), update it UpdateDataPointer(); } uint8_t rpDecrement = (_opCode >> 8) & 0x01; - if(rpDecrement && dest != 0x05) { + if (rpDecrement && dest != 0x05) + { //Destination was not the rom pointer (RP), decrement it _state.RP--; } @@ -389,7 +506,7 @@ void NecDsp::ExecAndReturn() { ExecOp(); _state.SP = (_state.SP - 1) & _stackMask; - _state.PC = _stack[_state.SP]; + _state.PC = _stack[_state.SP]; } void NecDsp::Jump() @@ -400,67 +517,107 @@ void NecDsp::Jump() uint32_t jmpCond = 0; uint16_t jmpType = (_opCode >> 13) & 0x1FF; - switch(jmpType) { - case 0x00: _state.PC = _state.SerialOut; break; + switch (jmpType) + { + case 0x00: _state.PC = _state.SerialOut; + break; - case 0x80: jmpCond = !_state.FlagsA.Carry; break; - case 0x82: jmpCond = _state.FlagsA.Carry; break; - case 0x84: jmpCond = !_state.FlagsB.Carry; break; - case 0x86: jmpCond = _state.FlagsB.Carry; break; + case 0x80: jmpCond = !_state.FlagsA.Carry; + break; + case 0x82: jmpCond = _state.FlagsA.Carry; + break; + case 0x84: jmpCond = !_state.FlagsB.Carry; + break; + case 0x86: jmpCond = _state.FlagsB.Carry; + break; - case 0x88: jmpCond = !_state.FlagsA.Zero; break; - case 0x8A: jmpCond = _state.FlagsA.Zero; break; - case 0x8C: jmpCond = !_state.FlagsB.Zero; break; - case 0x8E: jmpCond = _state.FlagsB.Zero; break; + case 0x88: jmpCond = !_state.FlagsA.Zero; + break; + case 0x8A: jmpCond = _state.FlagsA.Zero; + break; + case 0x8C: jmpCond = !_state.FlagsB.Zero; + break; + case 0x8E: jmpCond = _state.FlagsB.Zero; + break; - case 0x90: jmpCond = !_state.FlagsA.Overflow0; break; - case 0x92: jmpCond = _state.FlagsA.Overflow0; break; - case 0x94: jmpCond = !_state.FlagsB.Overflow0; break; - case 0x96: jmpCond = _state.FlagsB.Overflow0; break; - case 0x98: jmpCond = !_state.FlagsA.Overflow1; break; - case 0x9A: jmpCond = _state.FlagsA.Overflow1; break; - case 0x9C: jmpCond = !_state.FlagsB.Overflow1; break; - case 0x9E: jmpCond = _state.FlagsB.Overflow1; break; + case 0x90: jmpCond = !_state.FlagsA.Overflow0; + break; + case 0x92: jmpCond = _state.FlagsA.Overflow0; + break; + case 0x94: jmpCond = !_state.FlagsB.Overflow0; + break; + case 0x96: jmpCond = _state.FlagsB.Overflow0; + break; + case 0x98: jmpCond = !_state.FlagsA.Overflow1; + break; + case 0x9A: jmpCond = _state.FlagsA.Overflow1; + break; + case 0x9C: jmpCond = !_state.FlagsB.Overflow1; + break; + case 0x9E: jmpCond = _state.FlagsB.Overflow1; + break; - case 0xA0: jmpCond = !_state.FlagsA.Sign0; break; - case 0xA2: jmpCond = _state.FlagsA.Sign0; break; - case 0xA4: jmpCond = !_state.FlagsB.Sign0; break; - case 0xA6: jmpCond = _state.FlagsB.Sign0; break; - case 0xA8: jmpCond = !_state.FlagsA.Sign1; break; - case 0xAA: jmpCond = _state.FlagsA.Sign1; break; - case 0xAC: jmpCond = !_state.FlagsB.Sign1; break; - case 0xAE: jmpCond = _state.FlagsB.Sign1; break; + case 0xA0: jmpCond = !_state.FlagsA.Sign0; + break; + case 0xA2: jmpCond = _state.FlagsA.Sign0; + break; + case 0xA4: jmpCond = !_state.FlagsB.Sign0; + break; + case 0xA6: jmpCond = _state.FlagsB.Sign0; + break; + case 0xA8: jmpCond = !_state.FlagsA.Sign1; + break; + case 0xAA: jmpCond = _state.FlagsA.Sign1; + break; + case 0xAC: jmpCond = !_state.FlagsB.Sign1; + break; + case 0xAE: jmpCond = _state.FlagsB.Sign1; + break; - case 0xB0: jmpCond = !(_state.DP & 0x0F); break; - case 0xB1: jmpCond = _state.DP & 0x0F; break; - case 0xB2: jmpCond = (_state.DP & 0x0F) == 0x0F; break; - case 0xB3: jmpCond = (_state.DP & 0x0F) != 0x0F; break; + case 0xB0: jmpCond = !(_state.DP & 0x0F); + break; + case 0xB1: jmpCond = _state.DP & 0x0F; + break; + case 0xB2: jmpCond = (_state.DP & 0x0F) == 0x0F; + break; + case 0xB3: jmpCond = (_state.DP & 0x0F) != 0x0F; + break; - case 0xB4: jmpCond = !(_state.SR & NecDspStatusFlags::SerialInControl); break; - case 0xB6: jmpCond = _state.SR & NecDspStatusFlags::SerialInControl; break; - case 0xB8: jmpCond = !(_state.SR & NecDspStatusFlags::SerialOutControl); break; - case 0xBA: jmpCond = _state.SR & NecDspStatusFlags::SerialOutControl; break; - case 0xBC: jmpCond = !(_state.SR & NecDspStatusFlags::RequestForMaster); break; - case 0xBE: jmpCond = _state.SR & NecDspStatusFlags::RequestForMaster; break; + case 0xB4: jmpCond = !(_state.SR & NecDspStatusFlags::SerialInControl); + break; + case 0xB6: jmpCond = _state.SR & NecDspStatusFlags::SerialInControl; + break; + case 0xB8: jmpCond = !(_state.SR & NecDspStatusFlags::SerialOutControl); + break; + case 0xBA: jmpCond = _state.SR & NecDspStatusFlags::SerialOutControl; + break; + case 0xBC: jmpCond = !(_state.SR & NecDspStatusFlags::RequestForMaster); + break; + case 0xBE: jmpCond = _state.SR & NecDspStatusFlags::RequestForMaster; + break; - case 0x100: _state.PC = target & ~0x2000; break; - case 0x101: _state.PC = target | 0x2000; break; + case 0x100: _state.PC = target & ~0x2000; + break; + case 0x101: _state.PC = target | 0x2000; + break; - case 0x140: - _stack[_state.SP] = _state.PC; - _state.SP = (_state.SP + 1) & _stackMask; - _state.PC = target & ~0x2000; - break; + case 0x140: + _stack[_state.SP] = _state.PC; + _state.SP = (_state.SP + 1) & _stackMask; + _state.PC = target & ~0x2000; + break; - case 0x141: - _stack[_state.SP] = _state.PC; - _state.SP = (_state.SP + 1) & _stackMask; - _state.PC = target | 0x2000; - break; + case 0x141: + _stack[_state.SP] = _state.PC; + _state.SP = (_state.SP + 1) & _stackMask; + _state.PC = target | 0x2000; + break; } - if(jmpCond) { - if((_state.PC - 1 == target) && (jmpType == 0xBC || jmpType == 0xBE)) { + if (jmpCond) + { + if ((_state.PC - 1 == target) && (jmpType == 0xBC || jmpType == 0xBE)) + { //CPU is in a wait loop for RQM, skip emulation until the CPU reads/writes from the IO registers _inRqmLoop = true; } @@ -470,69 +627,82 @@ void NecDsp::Jump() void NecDsp::Load(uint8_t dest, uint16_t value) { - switch(dest) { - case 0x00: break; - case 0x01: _state.A = value; break; - case 0x02: _state.B = value; break; - case 0x03: _state.TR = value; break; - case 0x04: _state.DP = value; break; - case 0x05: _state.RP = value; break; + switch (dest) + { + case 0x00: break; + case 0x01: _state.A = value; + break; + case 0x02: _state.B = value; + break; + case 0x03: _state.TR = value; + break; + case 0x04: _state.DP = value; + break; + case 0x05: _state.RP = value; + break; - case 0x06: - _state.DR = value; - _state.SR |= NecDspStatusFlags::RequestForMaster; - break; + case 0x06: + _state.DR = value; + _state.SR |= NecDspStatusFlags::RequestForMaster; + break; - case 0x07: - _state.SR = (_state.SR & 0x907C) | (value & ~0x907C); - break; + case 0x07: + _state.SR = (_state.SR & 0x907C) | (value & ~0x907C); + break; - case 0x08: _state.SerialOut = value; break; - case 0x09: _state.SerialOut = value; break; - case 0x0A: _state.K = value; break; + case 0x08: _state.SerialOut = value; + break; + case 0x09: _state.SerialOut = value; + break; + case 0x0A: _state.K = value; + break; - case 0x0B: - _state.K = value; - _state.L = _dataRom[_state.RP & _dataMask]; - break; + case 0x0B: + _state.K = value; + _state.L = _dataRom[_state.RP & _dataMask]; + break; - case 0x0C: - _state.L = value; - _state.K = _ram[(_state.DP | 0x40) & _ramMask]; - break; + case 0x0C: + _state.L = value; + _state.K = _ram[(_state.DP | 0x40) & _ramMask]; + break; - case 0x0D: _state.L = value; break; - case 0x0E: _state.TRB = value; break; - case 0x0F: _ram[_state.DP & _ramMask] = value; break; + case 0x0D: _state.L = value; + break; + case 0x0E: _state.TRB = value; + break; + case 0x0F: _ram[_state.DP & _ramMask] = value; + break; - default: - throw std::runtime_error("DSP-1: invalid destination"); + default: + throw std::runtime_error("DSP-1: invalid destination"); } } uint16_t NecDsp::GetSourceValue(uint8_t source) { - switch(source) { - case 0x00: return _state.TRB; - case 0x01: return _state.A; - case 0x02: return _state.B; - case 0x03: return _state.TR; - case 0x04: return _state.DP; - case 0x05: return _state.RP; - case 0x06: return _dataRom[_state.RP & _dataMask]; - case 0x07: return 0x8000 - _state.FlagsA.Sign1; + switch (source) + { + case 0x00: return _state.TRB; + case 0x01: return _state.A; + case 0x02: return _state.B; + case 0x03: return _state.TR; + case 0x04: return _state.DP; + case 0x05: return _state.RP; + case 0x06: return _dataRom[_state.RP & _dataMask]; + case 0x07: return 0x8000 - _state.FlagsA.Sign1; - case 0x08: - _state.SR |= NecDspStatusFlags::RequestForMaster; - return _state.DR; + case 0x08: + _state.SR |= NecDspStatusFlags::RequestForMaster; + return _state.DR; - case 0x09: return _state.DR; - case 0x0A: return _state.SR; - case 0x0B: return _state.SerialIn; - case 0x0C: return _state.SerialIn; - case 0x0D: return _state.K; - case 0x0E: return _state.L; - case 0x0F: return _ram[_state.DP & _ramMask]; + case 0x09: return _state.DR; + case 0x0A: return _state.SR; + case 0x0B: return _state.SerialIn; + case 0x0C: return _state.SerialIn; + case 0x0D: return _state.K; + case 0x0E: return _state.L; + case 0x0F: return _ram[_state.DP & _ramMask]; } throw std::runtime_error("DSP-1: invalid source"); } @@ -572,13 +742,15 @@ NecDspState NecDsp::GetState() return _state; } -void NecDsp::Serialize(Serializer &s) +void NecDsp::Serialize(Serializer& s) { s.Stream( _state.A, _state.B, _state.DP, _state.DR, _state.K, _state.L, _state.M, _state.N, _state.PC, - _state.RP, _state.SerialIn, _state.SerialOut, _state.SP, _state.SR, _state.TR, _state.TRB, - _state.FlagsA.Carry, _state.FlagsA.Overflow0, _state.FlagsA.Overflow1, _state.FlagsA.Sign0, _state.FlagsA.Sign1, _state.FlagsA.Zero, - _state.FlagsB.Carry, _state.FlagsB.Overflow0, _state.FlagsB.Overflow1, _state.FlagsB.Sign0, _state.FlagsB.Sign1, _state.FlagsB.Zero + _state.RP, _state.SerialIn, _state.SerialOut, _state.SP, _state.SR, _state.TR, _state.TRB, + _state.FlagsA.Carry, _state.FlagsA.Overflow0, _state.FlagsA.Overflow1, _state.FlagsA.Sign0, _state.FlagsA.Sign1, + _state.FlagsA.Zero, + _state.FlagsB.Carry, _state.FlagsB.Overflow0, _state.FlagsB.Overflow1, _state.FlagsB.Sign0, _state.FlagsB.Sign1, + _state.FlagsB.Zero ); s.Stream(_opCode, _cycleCount, _inRqmLoop); @@ -591,77 +763,94 @@ void NecDsp::SetReg(NecDspRegister reg, uint16_t value) switch (reg) { case NecDspRegister::NecDspRegA: - { - _state.A = value; - } break; + { + _state.A = value; + } + break; case NecDspRegister::NecDspRegFlagsA: - { - _state.FlagsA.SetFlags(value & 0xFF); - } break; + { + _state.FlagsA.SetFlags(value & 0xFF); + } + break; case NecDspRegister::NecDspRegB: - { - _state.B = value; - } break; + { + _state.B = value; + } + break; case NecDspRegister::NecDspRegFlagsB: - { - _state.FlagsB.SetFlags(value & 0xFF); - } break; + { + _state.FlagsB.SetFlags(value & 0xFF); + } + break; case NecDspRegister::NecDspRegTR: - { - _state.TR = value; - } break; + { + _state.TR = value; + } + break; case NecDspRegister::NecDspRegTRB: - { - _state.TRB = value; - } break; + { + _state.TRB = value; + } + break; case NecDspRegister::NecDspRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case NecDspRegister::NecDspRegRP: - { - _state.RP = value; - } break; + { + _state.RP = value; + } + break; case NecDspRegister::NecDspRegDP: - { - _state.DP = value; - } break; + { + _state.DP = value; + } + break; case NecDspRegister::NecDspRegDR: - { - _state.DR = value; - } break; + { + _state.DR = value; + } + break; case NecDspRegister::NecDspRegSR: - { - _state.SR = value; - } break; + { + _state.SR = value; + } + break; case NecDspRegister::NecDspRegK: - { - _state.K = value; - } break; + { + _state.K = value; + } + break; case NecDspRegister::NecDspRegL: - { - _state.L = value; - } break; + { + _state.L = value; + } + break; case NecDspRegister::NecDspRegM: - { - _state.M = value; - } break; + { + _state.M = value; + } + break; case NecDspRegister::NecDspRegN: - { - _state.N = value; - } break; + { + _state.N = value; + } + break; case NecDspRegister::NecDspRegSerialOut: - { - _state.SerialOut = value; - } break; + { + _state.SerialOut = value; + } + break; case NecDspRegister::NecDspRegSerialIn: - { - _state.SerialIn = value; - } break; + { + _state.SerialIn = value; + } + break; case NecDspRegister::NecDspRegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; } } - diff --git a/Core/NecDsp.h b/Core/NecDsp.h index 184356a..53246e4 100644 --- a/Core/NecDsp.h +++ b/Core/NecDsp.h @@ -19,10 +19,10 @@ private: double _frequency = 7600000; uint32_t _opCode = 0; - uint8_t *_progRom = nullptr; - uint32_t *_prgCache = nullptr; - uint16_t *_dataRom = nullptr; - uint16_t *_ram = nullptr; + uint8_t* _progRom = nullptr; + uint32_t* _prgCache = nullptr; + uint16_t* _dataRom = nullptr; + uint16_t* _ram = nullptr; uint16_t _stack[16]; uint32_t _progSize = 0; @@ -51,12 +51,12 @@ private: void Load(uint8_t dest, uint16_t value); uint16_t GetSourceValue(uint8_t source); - NecDsp(CoprocessorType type, Console* console, vector &programRom, vector &dataRom); + NecDsp(CoprocessorType type, Console* console, vector& programRom, vector& dataRom); public: virtual ~NecDsp(); - static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector &embeddedFirmware); + static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector& embeddedFirmware); void Reset() override; void Run() override; @@ -65,12 +65,12 @@ public: void SaveBattery() override; void BuildProgramCache(); - + uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; - + uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t * output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; uint8_t* DebugGetProgramRom(); @@ -81,7 +81,7 @@ public: uint32_t DebugGetDataRamSize(); NecDspState GetState(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(NecDspRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/NecDspDebugger.cpp b/Core/NecDspDebugger.cpp index f8768c1..dec3ec1 100644 --- a/Core/NecDspDebugger.cpp +++ b/Core/NecDspDebugger.cpp @@ -32,14 +32,21 @@ void NecDspDebugger::Reset() void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo = { (int32_t)addr, type == MemoryOperationType::ExecOpCode ? SnesMemoryType::DspProgramRom : SnesMemoryType::DspDataRom }; - MemoryOperationInfo operation { (uint32_t)addr, value, type }; + AddressInfo addressInfo = { + (int32_t)addr, + type == MemoryOperationType::ExecOpCode ? SnesMemoryType::DspProgramRom : SnesMemoryType::DspDataRom + }; + MemoryOperationInfo operation{(uint32_t)addr, value, type}; - if(type == MemoryOperationType::ExecOpCode) { - if(_traceLogger->IsCpuLogged(CpuType::NecDsp) || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) { + if (type == MemoryOperationType::ExecOpCode) + { + if (_traceLogger->IsCpuLogged(CpuType::NecDsp) || _settings->CheckDebuggerFlag( + DebuggerFlags::NecDspDebuggerEnabled)) + { _disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp); - if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { + if (_traceLogger->IsCpuLogged(CpuType::NecDsp)) + { DebugState debugState; _debugger->GetState(debugState, true); @@ -50,7 +57,8 @@ void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationTy _prevProgramCounter = addr; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } } @@ -60,8 +68,8 @@ void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationTy void NecDspDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo { addr, SnesMemoryType::DspDataRam }; //Writes never affect the DSP ROM - MemoryOperationInfo operation { addr, value, type }; + AddressInfo addressInfo{addr, SnesMemoryType::DspDataRam}; //Writes never affect the DSP ROM + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); } @@ -74,17 +82,19 @@ void NecDspDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - - case StepType::StepOut: - case StepType::StepOver: - step.StepCount = 1; - break; + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::StepOut: + case StepType::StepOver: + step.StepCount = 1; + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -98,4 +108,4 @@ shared_ptr NecDspDebugger::GetCallstackManager() BreakpointManager* NecDspDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/NecDspDebugger.h b/Core/NecDspDebugger.h index e8df7c7..ab1ba53 100644 --- a/Core/NecDspDebugger.h +++ b/Core/NecDspDebugger.h @@ -37,4 +37,4 @@ public: void Step(int32_t stepCount, StepType type); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/NecDspDisUtils.cpp b/Core/NecDspDisUtils.cpp index 7d61229..7a4936c 100644 --- a/Core/NecDspDisUtils.cpp +++ b/Core/NecDspDisUtils.cpp @@ -7,129 +7,204 @@ #include "../Utilities/FastString.h" #include "DebugTypes.h" -void NecDspDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings* settings) +void NecDspDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { - constexpr const char* aluOperations[16] = { "NOP", "OR", "AND", "XOR", "SUB", "ADD", "SBC", "ADC", "DEC" , "INC", "CMP", "SHR1", "SHL1", "SHL2", "SHL4", "XCHG" }; - constexpr const char* sourceNames[16] = { "TRB", "A", "B", "TR", "DP", "RP", "ROM", "SGN", "DR", "DRNF", "SR", "SIM", "SIL" ,"K", "L", "MEM" }; - constexpr const char* destNames[16] = { "NON", "A", "B", "TR", "DP", "RP", "DR", "SR", "SOL", "SOM", "K", "KLR", "KLM", "L", "TRB", "MEM" }; - constexpr const char* dataPointerOp[4] = { "DPL:NOP", "DPL:INC", "DPL:DEC", "DPL:CLR" }; + constexpr const char* aluOperations[16] = { + "NOP", "OR", "AND", "XOR", "SUB", "ADD", "SBC", "ADC", "DEC", "INC", "CMP", "SHR1", "SHL1", "SHL2", "SHL4", "XCHG" + }; + constexpr const char* sourceNames[16] = { + "TRB", "A", "B", "TR", "DP", "RP", "ROM", "SGN", "DR", "DRNF", "SR", "SIM", "SIL", "K", "L", "MEM" + }; + constexpr const char* destNames[16] = { + "NON", "A", "B", "TR", "DP", "RP", "DR", "SR", "SOL", "SOM", "K", "KLR", "KLM", "L", "TRB", "MEM" + }; + constexpr const char* dataPointerOp[4] = {"DPL:NOP", "DPL:INC", "DPL:DEC", "DPL:CLR"}; FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); uint32_t opCode = *(uint32_t*)info.GetByteCode(); uint8_t operationType = (opCode >> 22) & 0x03; - if(operationType <= 1) { + if (operationType <= 1) + { //OP or RT uint8_t aluOperation = (opCode >> 16) & 0x0F; uint8_t source = (opCode >> 4) & 0x0F; uint8_t accSelect = (opCode >> 15) & 0x01; - if(aluOperation) { + if (aluOperation) + { str.WriteAll(aluOperations[aluOperation], " "); - if(aluOperation <= 7) { + if (aluOperation <= 7) + { uint8_t pSelect = (opCode >> 20) & 0x03; - switch(pSelect) { - case 0: str.Write("RAM,"); break; - case 1: str.WriteAll(sourceNames[source], ","); break; - case 2: str.Write("M,"); break; - case 3: str.Write("N,"); break; + switch (pSelect) + { + case 0: str.Write("RAM,"); + break; + case 1: str.WriteAll(sourceNames[source], ","); + break; + case 2: str.Write("M,"); + break; + case 3: str.Write("N,"); + break; } } str.Write(accSelect ? "B" : "A"); } - + uint8_t dest = opCode & 0x0F; - if(dest) { + if (dest) + { str.Delimiter(" | "); str.Write("MOV "); str.WriteAll(sourceNames[source], ","); str.Write(destNames[dest]); } - + uint8_t dpLow = (opCode >> 13) & 0x03; - if(dpLow) { + if (dpLow) + { str.Delimiter(" | "); str.Write(dataPointerOp[dpLow]); } uint8_t dpHighModify = (opCode >> 9) & 0x0F; - if(dpHighModify) { + if (dpHighModify) + { str.Delimiter(" | "); str.WriteAll("DPH:$", HexUtilities::ToHex(dpHighModify)); } uint8_t rpDecrement = (opCode >> 8) & 0x01; - if(rpDecrement) { + if (rpDecrement) + { str.Delimiter(" | "); str.Write("RP:DEC"); } - if(operationType == 1) { + if (operationType == 1) + { str.Delimiter(" | "); str.Write("RET"); - } else if(opCode == 0) { + } + else if (opCode == 0) + { str.Write("NOP"); } - } else if(operationType == 2) { + } + else if (operationType == 2) + { //Jump uint8_t bank = opCode & 0x03; uint16_t address = (opCode >> 2) & 0x7FF; uint16_t target = (memoryAddr & 0x2000) | (bank << 11) | address; - switch((opCode >> 13) & 0x1FF) { - case 0x00: str.Write("JMPSO"); target = 0; break; - case 0x80: str.Write("JNCA"); break; - case 0x82: str.Write("JCA"); break; - case 0x84: str.Write("JNCB"); break; - case 0x86: str.Write("JCB"); break; - case 0x88: str.Write("JNZA"); break; - case 0x8A: str.Write("JZA"); break; - case 0x8C: str.Write("JNZB"); break; - case 0x8E: str.Write("JZB"); break; - case 0x90: str.Write("JNOVA0"); break; - case 0x92: str.Write("JOVA0"); break; - case 0x94: str.Write("JNOVB0"); break; - case 0x96: str.Write("JOVB0"); break; - case 0x98: str.Write("JNOVA1"); break; - case 0x9A: str.Write("JOVA1"); break; - case 0x9C: str.Write("JNOVB1"); break; - case 0x9E: str.Write("JOVB1"); break; - case 0xA0: str.Write("JNSA0"); break; - case 0xA2: str.Write("JSA0"); break; - case 0xA4: str.Write("JNSB0"); break; - case 0xA6: str.Write("JSB0"); break; - case 0xA8: str.Write("JNSA1"); break; - case 0xAA: str.Write("JSA1"); break; - case 0xAC: str.Write("JNSB1"); break; - case 0xAE: str.Write("JSB1"); break; - case 0xB0: str.Write("JDPL0"); break; - case 0xB1: str.Write("JDPLN0"); break; - case 0xB2: str.Write("JDPLF"); break; - case 0xB3: str.Write("JDPLNF"); break; - case 0xB4: str.Write("JNSIAK"); break; - case 0xB6: str.Write("JSIAK"); break; - case 0xB8: str.Write("JNSOAK"); break; - case 0xBA: str.Write("JSOAK"); break; - case 0xBC: str.Write("JNRQM"); break; - case 0xBE: str.Write("JRQM"); break; - case 0x100: str.Write("LJMP"); target &= ~0x2000; break; - case 0x101: str.Write("HJMP"); target |= 0x2000; break; - case 0x140: str.Write("LCALL"); target &= ~0x2000; break; - case 0x141: str.Write("HCALL"); target |= 0x2000; break; - default: str.Write(""); break; + switch ((opCode >> 13) & 0x1FF) + { + case 0x00: str.Write("JMPSO"); + target = 0; + break; + case 0x80: str.Write("JNCA"); + break; + case 0x82: str.Write("JCA"); + break; + case 0x84: str.Write("JNCB"); + break; + case 0x86: str.Write("JCB"); + break; + case 0x88: str.Write("JNZA"); + break; + case 0x8A: str.Write("JZA"); + break; + case 0x8C: str.Write("JNZB"); + break; + case 0x8E: str.Write("JZB"); + break; + case 0x90: str.Write("JNOVA0"); + break; + case 0x92: str.Write("JOVA0"); + break; + case 0x94: str.Write("JNOVB0"); + break; + case 0x96: str.Write("JOVB0"); + break; + case 0x98: str.Write("JNOVA1"); + break; + case 0x9A: str.Write("JOVA1"); + break; + case 0x9C: str.Write("JNOVB1"); + break; + case 0x9E: str.Write("JOVB1"); + break; + case 0xA0: str.Write("JNSA0"); + break; + case 0xA2: str.Write("JSA0"); + break; + case 0xA4: str.Write("JNSB0"); + break; + case 0xA6: str.Write("JSB0"); + break; + case 0xA8: str.Write("JNSA1"); + break; + case 0xAA: str.Write("JSA1"); + break; + case 0xAC: str.Write("JNSB1"); + break; + case 0xAE: str.Write("JSB1"); + break; + case 0xB0: str.Write("JDPL0"); + break; + case 0xB1: str.Write("JDPLN0"); + break; + case 0xB2: str.Write("JDPLF"); + break; + case 0xB3: str.Write("JDPLNF"); + break; + case 0xB4: str.Write("JNSIAK"); + break; + case 0xB6: str.Write("JSIAK"); + break; + case 0xB8: str.Write("JNSOAK"); + break; + case 0xBA: str.Write("JSOAK"); + break; + case 0xBC: str.Write("JNRQM"); + break; + case 0xBE: str.Write("JRQM"); + break; + case 0x100: str.Write("LJMP"); + target &= ~0x2000; + break; + case 0x101: str.Write("HJMP"); + target |= 0x2000; + break; + case 0x140: str.Write("LCALL"); + target &= ~0x2000; + break; + case 0x141: str.Write("HCALL"); + target |= 0x2000; + break; + default: str.Write(""); + break; } str.Write(' '); - AddressInfo absAddress = { (int32_t)target*3, SnesMemoryType::DspProgramRom }; + AddressInfo absAddress = {(int32_t)target * 3, SnesMemoryType::DspProgramRom}; string label = labelManager->GetLabel(absAddress); - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex(target * 3)); - } else { + } + else + { str.Write(label, true); } - } else if(operationType == 3) { + } + else if (operationType == 3) + { //Load uint16_t value = opCode >> 6; uint8_t dest = opCode & 0x0F; diff --git a/Core/NecDspDisUtils.h b/Core/NecDspDisUtils.h index ef5cd75..16f2bdf 100644 --- a/Core/NecDspDisUtils.h +++ b/Core/NecDspDisUtils.h @@ -8,5 +8,6 @@ class EmuSettings; class NecDspDisUtils { 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); }; diff --git a/Core/NetMessage.h b/Core/NetMessage.h index 825f7fc..bef1ff8 100644 --- a/Core/NetMessage.h +++ b/Core/NetMessage.h @@ -23,8 +23,8 @@ protected: } public: - virtual ~NetMessage() - { + virtual ~NetMessage() + { } void Initialize() @@ -38,7 +38,7 @@ public: return _type; } - void Send(Socket &socket) + void Send(Socket& socket) { Serializer s(SaveStateManager::FileFormatVersion); Serialize(s); @@ -53,5 +53,5 @@ public: } protected: - virtual void Serialize(Serializer &s) = 0; + virtual void Serialize(Serializer& s) = 0; }; diff --git a/Core/NotificationManager.cpp b/Core/NotificationManager.cpp index aa5f50c..65ef516 100644 --- a/Core/NotificationManager.cpp +++ b/Core/NotificationManager.cpp @@ -6,8 +6,10 @@ void NotificationManager::RegisterNotificationListener(shared_ptr listener : _listeners) { - if(listener.lock() == notificationListener) { + for (weak_ptr listener : _listeners) + { + if (listener.lock() == notificationListener) + { //This listener is already registered, do nothing return; } @@ -41,9 +43,11 @@ void NotificationManager::SendNotification(ConsoleNotificationType type, void* p } //Iterate on a copy without using a lock - for(weak_ptr notificationListener : listeners) { + for (weak_ptr notificationListener : listeners) + { shared_ptr listener = notificationListener.lock(); - if(listener) { + if (listener) + { listener->ProcessNotification(type, parameter); } } diff --git a/Core/NotificationManager.h b/Core/NotificationManager.h index e38a39d..1a20a31 100644 --- a/Core/NotificationManager.h +++ b/Core/NotificationManager.h @@ -9,7 +9,7 @@ private: SimpleLock _lock; vector> _listenersToAdd; vector> _listeners; - + void CleanupNotificationListeners(); public: diff --git a/Core/NtscFilter.cpp b/Core/NtscFilter.cpp index 85103b5..0c04198 100644 --- a/Core/NtscFilter.cpp +++ b/Core/NtscFilter.cpp @@ -7,7 +7,7 @@ NtscFilter::NtscFilter(shared_ptr console) : BaseVideoFilter(console) { memset(&_ntscData, 0, sizeof(_ntscData)); - _ntscSetup = { }; + _ntscSetup = {}; snes_ntsc_init(&_ntscData, &_ntscSetup); _ntscBuffer = new uint32_t[SNES_NTSC_OUT_WIDTH(256) * 480]; } @@ -17,10 +17,10 @@ FrameInfo NtscFilter::GetFrameInfo() OverscanDimensions overscan = GetOverscan(); int widthDivider = _baseFrameInfo.Width == 512 ? 2 : 1; int heightMultiplier = _baseFrameInfo.Width == 512 ? 1 : 2; - + FrameInfo frameInfo; - frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / widthDivider) - overscan.Left*2 - overscan.Right*2; - frameInfo.Height = _baseFrameInfo.Height * heightMultiplier - overscan.Top*2 - overscan.Bottom*2; + frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / widthDivider) - overscan.Left * 2 - overscan.Right * 2; + frameInfo.Height = _baseFrameInfo.Height * heightMultiplier - overscan.Top * 2 - overscan.Bottom * 2; return frameInfo; } @@ -28,9 +28,13 @@ void NtscFilter::OnBeforeApplyFilter() { VideoConfig cfg = _console->GetSettings()->GetVideoConfig(); - if(_ntscSetup.hue != cfg.Hue / 100.0 || _ntscSetup.saturation != cfg.Saturation / 100.0 || _ntscSetup.brightness != cfg.Brightness / 100.0 || _ntscSetup.contrast != cfg.Contrast / 100.0 || - _ntscSetup.artifacts != cfg.NtscArtifacts || _ntscSetup.bleed != cfg.NtscBleed || _ntscSetup.fringing != cfg.NtscFringing || _ntscSetup.gamma != cfg.NtscGamma || - (_ntscSetup.merge_fields == 1) != cfg.NtscMergeFields || _ntscSetup.resolution != cfg.NtscResolution || _ntscSetup.sharpness != cfg.NtscSharpness) { + if (_ntscSetup.hue != cfg.Hue / 100.0 || _ntscSetup.saturation != cfg.Saturation / 100.0 || _ntscSetup.brightness != + cfg.Brightness / 100.0 || _ntscSetup.contrast != cfg.Contrast / 100.0 || + _ntscSetup.artifacts != cfg.NtscArtifacts || _ntscSetup.bleed != cfg.NtscBleed || _ntscSetup.fringing != cfg. + NtscFringing || _ntscSetup.gamma != cfg.NtscGamma || + (_ntscSetup.merge_fields == 1) != cfg.NtscMergeFields || _ntscSetup.resolution != cfg.NtscResolution || _ntscSetup + .sharpness != cfg.NtscSharpness) + { _ntscSetup.hue = cfg.Hue; _ntscSetup.saturation = cfg.Saturation; _ntscSetup.brightness = cfg.Brightness; @@ -47,39 +51,56 @@ void NtscFilter::OnBeforeApplyFilter() } } -void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer) +void NtscFilter::ApplyFilter(uint16_t* ppuOutputBuffer) { FrameInfo frameInfo = GetFrameInfo(); OverscanDimensions overscan = GetOverscan(); - + bool useHighResOutput = _baseFrameInfo.Width == 512; uint32_t baseWidth = SNES_NTSC_OUT_WIDTH(256); uint32_t xOffset = overscan.Left * 2; uint32_t yOffset = overscan.Top * 2 * baseWidth; - if(useHighResOutput) { - snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 4); - } else { - snes_ntsc_blit(&_ntscData, ppuOutputBuffer, 256, IsOddFrame() ? 0 : 1, 256, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 8); + if (useHighResOutput) + { + snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, _baseFrameInfo.Height, + _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 4); + } + else + { + snes_ntsc_blit(&_ntscData, ppuOutputBuffer, 256, IsOddFrame() ? 0 : 1, 256, _baseFrameInfo.Height, _ntscBuffer, + SNES_NTSC_OUT_WIDTH(256) * 8); } VideoConfig cfg = _console->GetSettings()->GetVideoConfig(); - if(cfg.ScanlineIntensity == 0) { - for(uint32_t i = 0; i < frameInfo.Height; i+=2) { - memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); - memcpy(GetOutputBuffer()+(i+1)*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); + if (cfg.ScanlineIntensity == 0) + { + for (uint32_t i = 0; i < frameInfo.Height; i += 2) + { + memcpy(GetOutputBuffer() + i * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); + memcpy(GetOutputBuffer() + (i + 1) * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); } - } else { + } + else + { uint8_t intensity = (uint8_t)((1.0 - cfg.ScanlineIntensity) * 255); - for(uint32_t i = 0; i < frameInfo.Height; i++) { - if(i & 0x01) { - uint32_t *in = _ntscBuffer + yOffset + xOffset + (i - 1) * baseWidth; - uint32_t *out = GetOutputBuffer() + i * frameInfo.Width; - for(uint32_t j = 0; j < frameInfo.Width; j++) { + for (uint32_t i = 0; i < frameInfo.Height; i++) + { + if (i & 0x01) + { + uint32_t* in = _ntscBuffer + yOffset + xOffset + (i - 1) * baseWidth; + uint32_t* out = GetOutputBuffer() + i * frameInfo.Width; + for (uint32_t j = 0; j < frameInfo.Width; j++) + { out[j] = ApplyScanlineEffect(in[j], intensity); } - } else { - memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); + } + else + { + memcpy(GetOutputBuffer() + i * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); } } } @@ -88,4 +109,4 @@ void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer) NtscFilter::~NtscFilter() { delete[] _ntscBuffer; -} \ No newline at end of file +} diff --git a/Core/NtscFilter.h b/Core/NtscFilter.h index 444bf4f..e93c81c 100644 --- a/Core/NtscFilter.h +++ b/Core/NtscFilter.h @@ -19,6 +19,6 @@ public: NtscFilter(shared_ptr console); virtual ~NtscFilter(); - virtual void ApplyFilter(uint16_t *ppuOutputBuffer); + virtual void ApplyFilter(uint16_t* ppuOutputBuffer); virtual FrameInfo GetFrameInfo(); -}; \ No newline at end of file +}; diff --git a/Core/Obc1.cpp b/Core/Obc1.cpp index 067d15f..b20651b 100644 --- a/Core/Obc1.cpp +++ b/Core/Obc1.cpp @@ -6,7 +6,7 @@ Obc1::Obc1(Console* console, uint8_t* saveRam, uint32_t saveRamSize) : BaseCoprocessor(SnesMemoryType::Register) { - MemoryMappings *mappings = console->GetMemoryManager()->GetMemoryMappings(); + MemoryMappings* mappings = console->GetMemoryManager()->GetMemoryMappings(); mappings->RegisterHandler(0x00, 0x3F, 0x6000, 0x7FFF, this); mappings->RegisterHandler(0x80, 0xBF, 0x6000, 0x7FFF, this); @@ -32,12 +32,13 @@ uint8_t Obc1::Read(uint32_t addr) { addr &= 0x1FFF; - switch(addr) { - case 0x1FF0: return ReadRam(GetLowAddress()); - case 0x1FF1: return ReadRam(GetLowAddress() + 1); - case 0x1FF2: return ReadRam(GetLowAddress() + 2); - case 0x1FF3: return ReadRam(GetLowAddress() + 3); - case 0x1FF4: return ReadRam(GetHighAddress()); + switch (addr) + { + case 0x1FF0: return ReadRam(GetLowAddress()); + case 0x1FF1: return ReadRam(GetLowAddress() + 1); + case 0x1FF2: return ReadRam(GetLowAddress() + 2); + case 0x1FF3: return ReadRam(GetLowAddress() + 3); + case 0x1FF4: return ReadRam(GetHighAddress()); } return ReadRam(addr); } @@ -46,18 +47,25 @@ void Obc1::Write(uint32_t addr, uint8_t value) { addr &= 0x1FFF; - switch(addr) { - case 0x1FF0: WriteRam(GetLowAddress(), value); break; - case 0x1FF1: WriteRam(GetLowAddress() + 1, value); break; - case 0x1FF2: WriteRam(GetLowAddress() + 2, value); break; - case 0x1FF3: WriteRam(GetLowAddress() + 3, value); break; - case 0x1FF4: { + switch (addr) + { + case 0x1FF0: WriteRam(GetLowAddress(), value); + break; + case 0x1FF1: WriteRam(GetLowAddress() + 1, value); + break; + case 0x1FF2: WriteRam(GetLowAddress() + 2, value); + break; + case 0x1FF3: WriteRam(GetLowAddress() + 3, value); + break; + case 0x1FF4: + { uint8_t shift = (ReadRam(0x1FF6) & 0x03) << 1; WriteRam(GetHighAddress(), ((value & 0x03) << shift) | (ReadRam(GetHighAddress()) & ~(0x03 << shift))); break; } - default: WriteRam(addr, value); break; + default: WriteRam(addr, value); + break; } } @@ -78,7 +86,7 @@ uint16_t Obc1::GetHighAddress() return (GetBaseAddress() | ((ReadRam(0x1FF6) & 0x7F) >> 2)) + 0x200; } -void Obc1::Serialize(Serializer &s) +void Obc1::Serialize(Serializer& s) { } @@ -87,12 +95,12 @@ uint8_t Obc1::Peek(uint32_t addr) return 0; } -void Obc1::PeekBlock(uint32_t addr, uint8_t *output) +void Obc1::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo Obc1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; -} \ No newline at end of file + return {-1, SnesMemoryType::Register}; +} diff --git a/Core/Obc1.h b/Core/Obc1.h index 189417f..7acb45f 100644 --- a/Core/Obc1.h +++ b/Core/Obc1.h @@ -7,7 +7,7 @@ class Console; class Obc1 : public BaseCoprocessor { private: - uint8_t *_ram; + uint8_t* _ram; uint32_t _mask; uint16_t GetBaseAddress(); @@ -25,9 +25,9 @@ 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; + void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; -}; \ No newline at end of file +}; diff --git a/Core/PcmReader.cpp b/Core/PcmReader.cpp index 04d63e9..68c6198 100644 --- a/Core/PcmReader.cpp +++ b/Core/PcmReader.cpp @@ -21,15 +21,18 @@ PcmReader::~PcmReader() bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) { - if(_file) { + if (_file) + { _file.close(); } _file.open(filename, ios::binary); - if(_file) { + if (_file) + { _file.seekg(0, ios::end); _fileSize = (uint32_t)_file.tellg(); - if(_fileSize < 12) { + if (_fileSize < 12) + { return false; } @@ -53,7 +56,9 @@ bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) _resampler.Reset(); return true; - } else { + } + else + { _done = true; return false; } @@ -66,7 +71,8 @@ bool PcmReader::IsPlaybackOver() void PcmReader::SetSampleRate(uint32_t sampleRate) { - if(sampleRate != _sampleRate) { + if (sampleRate != _sampleRate) + { _sampleRate = sampleRate; _resampler.SetSampleRates(PcmReader::PcmSampleRate, _sampleRate); @@ -78,7 +84,7 @@ void PcmReader::SetLoopFlag(bool loop) _loop = loop; } -void PcmReader::ReadSample(int16_t &left, int16_t &right) +void PcmReader::ReadSample(int16_t& left, int16_t& right) { uint8_t val[4]; _file.get(((char*)val)[0]); @@ -96,7 +102,8 @@ void PcmReader::LoadSamples(uint32_t samplesToLoad) int16_t left = 0; int16_t right = 0; - for(uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i+=4) { + for (uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i += 4) + { ReadSample(left, right); _pcmBuffer.push_back(left); @@ -108,42 +115,51 @@ void PcmReader::LoadSamples(uint32_t samplesToLoad) _fileOffset += 4; samplesRead++; - if(samplesRead < samplesToLoad && i + 4 >= _fileSize) { - if(_loop) { + if (samplesRead < samplesToLoad && i + 4 >= _fileSize) + { + if (_loop) + { i = _loopOffset * 4 + 8; _fileOffset = i; _file.seekg(_fileOffset, ios::beg); - } else { + } + else + { _done = true; } } } } -void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume) +void PcmReader::ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { - if(_done) { + if (_done) + { return; } int32_t samplesNeeded = (int32_t)sampleCount - _leftoverSampleCount; - if(samplesNeeded > 0) { + if (samplesNeeded > 0) + { uint32_t samplesToLoad = samplesNeeded * PcmReader::PcmSampleRate / _sampleRate + 2; LoadSamples(samplesToLoad); } - uint32_t samplesRead = _resampler.Resample(_pcmBuffer.data(), (uint32_t)_pcmBuffer.size() / 2, _outputBuffer + _leftoverSampleCount*2); + uint32_t samplesRead = _resampler.Resample(_pcmBuffer.data(), (uint32_t)_pcmBuffer.size() / 2, + _outputBuffer + _leftoverSampleCount * 2); _pcmBuffer.clear(); uint32_t samplesToProcess = std::min((uint32_t)sampleCount * 2, (samplesRead + _leftoverSampleCount) * 2); - for(uint32_t i = 0; i < samplesToProcess; i++) { + for (uint32_t i = 0; i < samplesToProcess; i++) + { buffer[i] += (int16_t)((int32_t)_outputBuffer[i] * volume / 255); } //Calculate count of extra samples that couldn't be mixed with the rest of the audio and copy them to the beginning of the buffer //These will be mixed on the next call to ApplySamples _leftoverSampleCount = std::max(0, (int32_t)(samplesRead + _leftoverSampleCount) - (int32_t)sampleCount); - for(uint32_t i = 0; i < _leftoverSampleCount*2; i++) { + for (uint32_t i = 0; i < _leftoverSampleCount * 2; i++) + { _outputBuffer[i] = _outputBuffer[samplesToProcess + i]; } } @@ -151,4 +167,4 @@ void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume uint32_t PcmReader::GetOffset() { return _fileOffset; -} \ No newline at end of file +} diff --git a/Core/PcmReader.h b/Core/PcmReader.h index e81975a..4b1ca54 100644 --- a/Core/PcmReader.h +++ b/Core/PcmReader.h @@ -29,7 +29,7 @@ private: uint32_t _sampleRate; void LoadSamples(uint32_t samplesToLoad); - void ReadSample(int16_t &left, int16_t &right); + void ReadSample(int16_t& left, int16_t& right); public: PcmReader(); diff --git a/Core/PlayerListMessage.h b/Core/PlayerListMessage.h index cb7167e..8673978 100644 --- a/Core/PlayerListMessage.h +++ b/Core/PlayerListMessage.h @@ -8,19 +8,24 @@ private: vector _playerList; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { - if(s.IsSaving()) { + if (s.IsSaving()) + { uint32_t playerCount = (uint32_t)_playerList.size(); s.Stream(playerCount); - for(uint32_t i = 0; i < playerCount; i++) { + for (uint32_t i = 0; i < playerCount; i++) + { s.Stream(_playerList[i].Name, _playerList[i].ControllerPort, _playerList[i].IsHost); } - } else { + } + else + { uint32_t playerCount = 0; s.Stream(playerCount); - - for(uint32_t i = 0; i < playerCount; i++) { + + for (uint32_t i = 0; i < playerCount; i++) + { PlayerInfo playerInfo; s.Stream(playerInfo.Name, playerInfo.ControllerPort, playerInfo.IsHost); _playerList.push_back(playerInfo); @@ -29,7 +34,9 @@ protected: } public: - PlayerListMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + PlayerListMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } PlayerListMessage(vector playerList) : NetMessage(MessageType::PlayerList) { @@ -40,4 +47,4 @@ public: { return _playerList; } -}; \ No newline at end of file +}; diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 5e3e55d..1531210 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -18,14 +18,14 @@ #include "../Utilities/Serializer.h" static constexpr uint8_t _oamSizes[8][2][2] = { - { { 1, 1 }, { 2, 2 } }, //8x8 + 16x16 - { { 1, 1 }, { 4, 4 } }, //8x8 + 32x32 - { { 1, 1 }, { 8, 8 } }, //8x8 + 64x64 - { { 2, 2 }, { 4, 4 } }, //16x16 + 32x32 - { { 2, 2 }, { 8, 8 } }, //16x16 + 64x64 - { { 4, 4 }, { 8, 8 } }, //32x32 + 64x64 - { { 2, 4 }, { 4, 8 } }, //16x32 + 32x64 - { { 2, 4 }, { 4, 4 } } //16x32 + 32x32 + {{1, 1}, {2, 2}}, //8x8 + 16x16 + {{1, 1}, {4, 4}}, //8x8 + 32x32 + {{1, 1}, {8, 8}}, //8x8 + 64x64 + {{2, 2}, {4, 4}}, //16x16 + 32x32 + {{2, 2}, {8, 8}}, //16x16 + 64x64 + {{4, 4}, {8, 8}}, //32x32 + 64x64 + {{2, 4}, {4, 8}}, //16x32 + 32x64 + {{2, 4}, {4, 4}} //16x32 + 32x32 }; Ppu::Ppu(Console* console) @@ -56,11 +56,12 @@ void Ppu::PowerOn() _memoryManager = _console->GetMemoryManager().get(); _currentBuffer = _outputBuffers[0]; - + _state = {}; _state.ForcedVblank = true; _state.VramIncrementValue = 1; - if(_settings->GetEmulationConfig().EnableRandomPowerOnState) { + if (_settings->GetEmulationConfig().EnableRandomPowerOnState) + { RandomizeState(); } @@ -69,7 +70,7 @@ void Ppu::PowerOn() _settings->InitializeRam(_oamRam, Ppu::SpriteRamSize); memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes)); - + UpdateNmiScanline(); } @@ -94,11 +95,16 @@ uint16_t Ppu::GetCycle() { //"normally dots 323 and 327 are 6 master cycles instead of 4." uint16_t hClock = _memoryManager->GetHClock(); - if(hClock <= 1292) { + if (hClock <= 1292) + { return hClock >> 2; - } else if(hClock <= 1310) { + } + else if (hClock <= 1310) + { return (hClock - 2) >> 2; - } else { + } + else + { return (hClock - 4) >> 2; } } @@ -120,9 +126,10 @@ PpuState Ppu::GetState() return state; } -void Ppu::GetState(PpuState &state, bool returnPartialState) +void Ppu::GetState(PpuState& state, bool returnPartialState) { - if(!returnPartialState) { + if (!returnPartialState) + { state = _state; } state.Cycle = GetCycle(); @@ -131,42 +138,53 @@ void Ppu::GetState(PpuState &state, bool returnPartialState) state.FrameCount = _frameCount; } -template +template void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) { /* The current layer's options */ - LayerConfig &config = _state.Layers[layerIndex]; + LayerConfig& config = _state.Layers[layerIndex]; uint16_t vScroll = config.VScroll; - uint16_t hScroll = hiResMode ? (config.HScroll << 1) : config.HScroll; - if(_hOffset || _vOffset) { + uint16_t hScroll = hiResMode ? (config.HScroll << 1) : config.HScroll; + if (_hOffset || _vOffset) + { uint16_t enableBit = layerIndex == 0 ? 0x2000 : 0x4000; - if(_state.BgMode == 4) { - if((_hOffset & 0x8000) == 0 && (_hOffset & enableBit)) { + if (_state.BgMode == 4) + { + if ((_hOffset & 0x8000) == 0 && (_hOffset & enableBit)) + { hScroll = (hScroll & 0x07) | (_hOffset & 0x3F8); } - if((_hOffset & 0x8000) != 0 && (_hOffset & enableBit)) { + if ((_hOffset & 0x8000) != 0 && (_hOffset & enableBit)) + { vScroll = (_hOffset & 0x3FF); } - } else { - if(_hOffset & enableBit) { + } + else + { + if (_hOffset & enableBit) + { hScroll = (hScroll & 0x07) | (_hOffset & 0x3F8); } - if(_vOffset & enableBit) { + if (_vOffset & enableBit) + { vScroll = (_vOffset & 0x3FF); } } } - if(hiResMode) { + if (hiResMode) + { hScroll >>= 1; } uint16_t realY = IsDoubleHeight() ? (_oddFrame ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; - if(_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) { + if (_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; - if(IsDoubleHeight()) { + if (IsDoubleHeight()) + { realY -= _state.MosaicSize - _mosaicScanlineCounter; } } @@ -182,7 +200,8 @@ void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) /* The current column index (in terms of 8x8 or 16x16 tiles) */ uint16_t column = columnIndex + (hScroll >> 3); - if(!hiResMode && config.LargeTiles) { + if (!hiResMode && config.LargeTiles) + { //For 16x16 tiles, need to return the same tile for 2 columns 8 pixel columns in a row column >>= 1; } @@ -193,11 +212,11 @@ void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) _layerData[layerIndex].Tiles[columnIndex].VScroll = vScroll; } -template +template void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) { - LayerConfig &config = _state.Layers[layerIndex]; - TileData &tileData = _layerData[layerIndex].Tiles[column]; + LayerConfig& config = _state.Layers[layerIndex]; + TileData& tileData = _layerData[layerIndex].Tiles[column]; uint16_t tilemapData = tileData.TilemapData; bool largeTileWidth = hiResMode || config.LargeTiles; @@ -207,22 +226,26 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) uint16_t realY = IsDoubleHeight() ? (_oddFrame ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; - if(_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) { + if (_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; - if(IsDoubleHeight()) { + if (IsDoubleHeight()) + { realY -= _state.MosaicSize - _mosaicScanlineCounter + (_oddFrame ? 1 : 0); } } bool useSecondTile = secondTile; - if(!hiResMode && config.LargeTiles) { + if (!hiResMode && config.LargeTiles) + { //For 16x16 tiles, need to return the 2nd part of the tile every other column useSecondTile = (((column << 3) + config.HScroll) & 0x08) == 0x08; } uint16_t tileIndex = tilemapData & 0x3FF; - if(largeTileWidth) { + if (largeTileWidth) + { tileIndex = ( tileIndex + (config.LargeTiles ? (((realY + tileData.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + @@ -231,7 +254,7 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) } uint16_t tileStart = config.ChrAddress + tileIndex * 4 * bpp; - + uint8_t baseYOffset = (realY + tileData.VScroll) & 0x07; uint8_t yOffset = vMirror ? (7 - baseYOffset) : baseYOffset; @@ -241,7 +264,8 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) void Ppu::GetHorizontalOffsetByte(uint8_t columnIndex) { - uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & (_state.Layers[2].DoubleWidth ? 0x3F : 0x1F); + uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & ( + _state.Layers[2].DoubleWidth ? 0x3F : 0x1F); uint16_t rowOffset = (_state.Layers[2].VScroll >> 3) & (_state.Layers[2].DoubleHeight ? 0x3F : 0x1F); _hOffset = _vram[(_state.Layers[2].TilemapAddress + columnOffset + (rowOffset << 5)) & 0x7FFF]; @@ -249,129 +273,217 @@ void Ppu::GetHorizontalOffsetByte(uint8_t columnIndex) void Ppu::GetVerticalOffsetByte(uint8_t columnIndex) { - uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & (_state.Layers[2].DoubleWidth ? 0x3F : 0x1F); + uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & ( + _state.Layers[2].DoubleWidth ? 0x3F : 0x1F); uint16_t rowOffset = (_state.Layers[2].VScroll >> 3) & (_state.Layers[2].DoubleHeight ? 0x3F : 0x1F); uint16_t tileOffset = columnOffset + (rowOffset << 5); //The vertical offset is 0x40 bytes later - but wraps around within the tilemap based on the tilemap size (0x800 or 0x1000 bytes) - uint16_t vOffsetAddr = _state.Layers[2].TilemapAddress + ((tileOffset + 0x20) & (_state.Layers[2].DoubleHeight ? 0x7FF : 0x3FF)); + uint16_t vOffsetAddr = _state.Layers[2].TilemapAddress + ((tileOffset + 0x20) & (_state.Layers[2].DoubleHeight + ? 0x7FF + : 0x3FF)); _vOffset = _vram[vOffsetAddr & 0x7FFF]; } void Ppu::FetchTileData() { - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { return; } - if(_fetchBgStart == 0) { + if (_fetchBgStart == 0) + { _hOffset = 0; _vOffset = 0; } - if(_state.BgMode == 0) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(3, x >> 3); break; - case 1: GetTilemapData(2, x >> 3); break; - case 2: GetTilemapData(1, x >> 3); break; - case 3: GetTilemapData(0, x >> 3); break; + if (_state.BgMode == 0) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(3, x >> 3); + break; + case 1: GetTilemapData(2, x >> 3); + break; + case 2: GetTilemapData(1, x >> 3); + break; + case 3: GetTilemapData(0, x >> 3); + break; - case 4: GetChrData(3, x >> 3, 0); break; - case 5: GetChrData(2, x >> 3, 0); break; - case 6: GetChrData(1, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 0); break; + case 4: GetChrData(3, x >> 3, 0); + break; + case 5: GetChrData(2, x >> 3, 0); + break; + case 6: GetChrData(1, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 0); + break; } } - } else if(_state.BgMode == 1) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(2, x >> 3); break; - case 1: GetTilemapData(1, x >> 3); break; - case 2: GetTilemapData(0, x >> 3); break; - case 3: GetChrData(2, x >> 3, 0); break; - case 4: GetChrData(1, x >> 3, 0); break; - case 5: GetChrData(1, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + } + else if (_state.BgMode == 1) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(2, x >> 3); + break; + case 1: GetTilemapData(1, x >> 3); + break; + case 2: GetTilemapData(0, x >> 3); + break; + case 3: GetChrData(2, x >> 3, 0); + break; + case 4: GetChrData(1, x >> 3, 0); + break; + case 5: GetChrData(1, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 2) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 2) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; - case 3: GetVerticalOffsetByte(x >> 3); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; + case 3: GetVerticalOffsetByte(x >> 3); + break; - case 4: GetChrData(1, x >> 3, 0); break; - case 5: GetChrData(1, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 4: GetChrData(1, x >> 3, 0); + break; + case 5: GetChrData(1, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 3) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 3) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetChrData(1, x >> 3, 0); break; - case 3: GetChrData(1, x >> 3, 1); break; + case 2: GetChrData(1, x >> 3, 0); + break; + case 3: GetChrData(1, x >> 3, 1); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 2); break; - case 7: GetChrData(0, x >> 3, 3); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 2); + break; + case 7: GetChrData(0, x >> 3, 3); + break; } } - } else if(_state.BgMode == 4) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 4) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; - case 3: GetChrData(1, x >> 3, 0); break; + case 3: GetChrData(1, x >> 3, 0); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 2); break; - case 7: GetChrData(0, x >> 3, 3); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 2); + break; + case 7: GetChrData(0, x >> 3, 3); + break; } } - } else if(_state.BgMode == 5) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 5) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetChrData(1, x >> 3, 0); break; - case 3: GetChrData(1, x >> 3, 0); break; + case 2: GetChrData(1, x >> 3, 0); + break; + case 3: GetChrData(1, x >> 3, 0); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 6) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 6) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; - case 3: GetVerticalOffsetByte(x >> 3); break; - - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; + case 3: GetVerticalOffsetByte(x >> 3); + break; + + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } } @@ -379,32 +491,39 @@ void Ppu::FetchTileData() bool Ppu::ProcessEndOfScanline(uint16_t hClock) { - if(hClock >= 1364 || (hClock == 1360 && _scanline == 240 && _oddFrame && !_state.ScreenInterlace)) { + if (hClock >= 1364 || (hClock == 1360 && _scanline == 240 && _oddFrame && !_state.ScreenInterlace)) + { //"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles." - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); - if(_scanline == 0) { + if (_scanline == 0) + { _overscanFrame = _state.OverscanMode; _mosaicScanlineCounter = _state.MosaicEnabled ? _state.MosaicSize + 1 : 0; //Update overclock timings once per frame UpdateNmiScanline(); - if(!_skipRender) { - if(!_interlacedFrame) { + if (!_skipRender) + { + if (!_interlacedFrame) + { _currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; } - + //If we're not skipping this frame, reset the high resolution/interlace flags _useHighResOutput = IsDoubleWidth() || _state.ScreenInterlace; _interlacedFrame = _state.ScreenInterlace; } } - - if(_mosaicScanlineCounter) { + + if (_mosaicScanlineCounter) + { _mosaicScanlineCounter--; - if(_state.MosaicEnabled && !_mosaicScanlineCounter) { + if (_state.MosaicEnabled && !_mosaicScanlineCounter) + { _mosaicScanlineCounter = _state.MosaicSize; } } @@ -421,8 +540,10 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) memset(_hasSpritePriority, 0, sizeof(_hasSpritePriority)); memcpy(_spritePriority, _spritePriorityCopy, sizeof(_spritePriority)); - for(int i = 0; i < 255; i++) { - if(_spritePriority[i] < 4) { + for (int i = 0; i < 255; i++) + { + if (_spritePriority[i] < 4) + { _hasSpritePriority[_spritePriority[i]] = true; } } @@ -438,18 +559,21 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) _scanline++; - if(_scanline == _nmiScanline) { + if (_scanline == _nmiScanline) + { ProcessLocationLatchRequest(); _latchRequest = false; //Reset OAM address at the start of vblank? - if(!_state.ForcedVblank) { + if (!_state.ForcedVblank) + { //TODO, the timing of this may be slightly off? should happen at H=10 based on anomie's docs _internalOamAddress = (_state.OamRamAddress << 1); } VideoConfig cfg = _settings->GetVideoConfig(); - _configVisibleLayers = (cfg.HideBgLayer0 ? 0 : 1) | (cfg.HideBgLayer1 ? 0 : 2) | (cfg.HideBgLayer2 ? 0 : 4) | (cfg.HideBgLayer3 ? 0 : 8) | (cfg.HideSprites ? 0 : 16); + _configVisibleLayers = (cfg.HideBgLayer0 ? 0 : 1) | (cfg.HideBgLayer1 ? 0 : 2) | (cfg.HideBgLayer2 ? 0 : 4) | ( + cfg.HideBgLayer3 ? 0 : 8) | (cfg.HideSprites ? 0 : 16); _console->ProcessEvent(EventType::EndFrame); @@ -459,7 +583,9 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) SendFrame(); _console->ProcessEndOfFrame(); - } else if(_scanline >= _vblankEndScanline + 1) { + } + else if (_scanline >= _vblankEndScanline + 1) + { //"Frames are 262 scanlines in non-interlace mode, while in interlace mode frames with $213f.7=0 are 263 scanlines" _oddFrame ^= 1; _regs->SetNmiFlag(false); @@ -475,8 +601,9 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) (_settings->GetEmulationSpeed() == 0 || _settings->GetEmulationSpeed() > 150) && _frameSkipTimer.GetElapsedMS() < 10 ); - - if(_console->IsRunAheadFrame()) { + + if (_console->IsRunAheadFrame()) + { _skipRender = true; } @@ -493,14 +620,20 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) void Ppu::UpdateSpcState() { //When using overclocking, turn off the SPC during the extra scanlines - if(_overclockEnabled && _scanline > _vblankStartScanline) { - if(_scanline > _adjustedVblankEndScanline) { + if (_overclockEnabled && _scanline > _vblankStartScanline) + { + if (_scanline > _adjustedVblankEndScanline) + { //Disable APU for extra lines after NMI _spc->SetSpcState(false); - } else if(_scanline >= _vblankStartScanline && _scanline < _nmiScanline) { + } + else if (_scanline >= _vblankStartScanline && _scanline < _nmiScanline) + { //Disable APU for extra lines before NMI _spc->SetSpcState(false); - } else { + } + else + { _spc->SetSpcState(true); } } @@ -509,16 +642,25 @@ void Ppu::UpdateSpcState() void Ppu::UpdateNmiScanline() { EmulationConfig cfg = _settings->GetEmulationConfig(); - if(_console->GetRegion() == ConsoleRegion::Ntsc) { - if(!_state.ScreenInterlace || _oddFrame) { + if (_console->GetRegion() == ConsoleRegion::Ntsc) + { + if (!_state.ScreenInterlace || _oddFrame) + { _baseVblankEndScanline = 261; - } else { + } + else + { _baseVblankEndScanline = 262; } - } else { - if(!_state.ScreenInterlace || _oddFrame) { + } + else + { + if (!_state.ScreenInterlace || _oddFrame) + { _baseVblankEndScanline = 311; - } else { + } + else + { _baseVblankEndScanline = 312; } } @@ -533,18 +675,25 @@ void Ppu::UpdateNmiScanline() uint16_t Ppu::GetRealScanline() { - if(!_overclockEnabled) { + if (!_overclockEnabled) + { return _scanline; } - if(_scanline > _vblankStartScanline && _scanline <= _nmiScanline) { + if (_scanline > _vblankStartScanline && _scanline <= _nmiScanline) + { //Pretend to be just before vblank until extra scanlines are over return _vblankStartScanline - 1; - } else if(_scanline > _nmiScanline) { - if(_scanline > _adjustedVblankEndScanline) { + } + else if (_scanline > _nmiScanline) + { + if (_scanline > _adjustedVblankEndScanline) + { //Pretend to be at the end of vblank until extra scanlines are over return _baseVblankEndScanline; - } else { + } + else + { //Number the regular scanlines as they would normally be return _scanline - _nmiScanline + _vblankStartScanline; } @@ -565,26 +714,36 @@ uint16_t Ppu::GetLastScanline() void Ppu::EvaluateNextLineSprites() { - if(_spriteEvalStart == 0) { + if (_spriteEvalStart == 0) + { _spriteCount = 0; _oamEvaluationIndex = _state.EnableOamPriority ? ((_internalOamAddress & 0x1FC) >> 2) : 0; } - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { return; } - for(int i = _spriteEvalStart; i <= _spriteEvalEnd; i++) { - if(!(i & 0x01)) { + for (int i = _spriteEvalStart; i <= _spriteEvalEnd; i++) + { + if (!(i & 0x01)) + { //First cycle, read X & Y and high oam byte FetchSpritePosition(_oamEvaluationIndex << 2); - } else { + } + else + { //Second cycle: Check if sprite is in range, if so, keep its index - if(_currentSprite.IsVisible(_scanline, _state.ObjInterlace)) { - if(_spriteCount < 32) { + if (_currentSprite.IsVisible(_scanline, _state.ObjInterlace)) + { + if (_spriteCount < 32) + { _spriteIndexes[_spriteCount] = _oamEvaluationIndex; _spriteCount++; - } else { + } + else + { _rangeOver = true; } } @@ -596,13 +755,15 @@ void Ppu::EvaluateNextLineSprites() void Ppu::FetchSpriteData() { //From H=272 to 339, fetch a single word of CHR data on every cycle (for up to 34 sprites) - if(_fetchSpriteStart == 0) { + if (_fetchSpriteStart == 0) + { memset(_spritePriorityCopy, 0xFF, sizeof(_spritePriorityCopy)); _spriteTileCount = 0; _currentSprite.Index = 0xFF; - if(_spriteCount == 0) { + if (_spriteCount == 0) + { _spriteFetchingDone = true; return; } @@ -610,27 +771,36 @@ void Ppu::FetchSpriteData() _oamTimeIndex = _spriteIndexes[_spriteCount - 1]; } - for(int x = _fetchSpriteStart; x <= _fetchSpriteEnd; x++) { - if(x >= 2) { + for (int x = _fetchSpriteStart; x <= _fetchSpriteEnd; x++) + { + if (x >= 2) + { //Fetch the tile using the OAM data loaded on the past 2 cycles, before overwriting it in FetchSpriteAttributes below - if(!_state.ForcedVblank) { + if (!_state.ForcedVblank) + { FetchSpriteTile(x & 0x01); } - if((x & 1) && _spriteCount == 0 && _currentSprite.ColumnOffset == 0) { + if ((x & 1) && _spriteCount == 0 && _currentSprite.ColumnOffset == 0) + { //End this step _spriteFetchingDone = true; break; } } - if(_spriteCount > 0) { - if(x & 1) { + if (_spriteCount > 0) + { + if (x & 1) + { FetchSpriteAttributes((_oamTimeIndex << 2) | 0x02); - if(_spriteCount > 0) { + if (_spriteCount > 0) + { _oamTimeIndex = _spriteIndexes[_spriteCount - 1]; } - } else { + } + else + { FetchSpritePosition(_oamTimeIndex << 2); } } @@ -651,11 +821,13 @@ void Ppu::FetchSpritePosition(uint16_t oamAddress) _currentSprite.X = (int16_t)((sign | (oamValue & 0xFF)) << 7) >> 7; _currentSprite.Y = (oamValue >> 8); _currentSprite.Width = _oamSizes[_state.OamMode][largeSprite][0] << 3; - - if(spriteIndex != _currentSprite.Index) { + + if (spriteIndex != _currentSprite.Index) + { _currentSprite.Index = oamAddress >> 2; _currentSprite.ColumnOffset = (_currentSprite.Width / 8); - if(_currentSprite.X <= -8 && _currentSprite.X != -256) { + if (_currentSprite.X <= -8 && _currentSprite.X != -256) + { //Skip the first tiles of the sprite (because the tiles are hidden to the left of the screen) _currentSprite.ColumnOffset += _currentSprite.X / 8; } @@ -668,7 +840,8 @@ void Ppu::FetchSpritePosition(uint16_t oamAddress) void Ppu::FetchSpriteAttributes(uint16_t oamAddress) { _spriteTileCount++; - if(_spriteTileCount > 34) { + if (_spriteTileCount > 34) + { _timeOver = true; } @@ -679,20 +852,24 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) _currentSprite.HorizontalMirror = (flags & 0x40) != 0; _currentSprite.ColumnOffset--; - + uint8_t yOffset; int rowOffset; int yGap = (_scanline - _currentSprite.Y); - if(_state.ObjInterlace) { + if (_state.ObjInterlace) + { yGap <<= 1; yGap |= _oddFrame; } bool verticalMirror = (flags & 0x80) != 0; - if(verticalMirror) { + if (verticalMirror) + { yOffset = (_currentSprite.Height - 1 - yGap) & 0x07; rowOffset = (_currentSprite.Height - 1 - yGap) >> 3; - } else { + } + else + { yOffset = yGap & 0x07; rowOffset = yGap >> 3; } @@ -701,7 +878,9 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) uint8_t tileRow = (_oamRam[oamAddress] & 0xF0) >> 4; uint8_t tileColumn = _oamRam[oamAddress] & 0x0F; uint8_t row = (tileRow + rowOffset) & 0x0F; - uint8_t columnOffset = _currentSprite.HorizontalMirror ? _currentSprite.ColumnOffset : (columnCount - _currentSprite.ColumnOffset - 1); + uint8_t columnOffset = _currentSprite.HorizontalMirror + ? _currentSprite.ColumnOffset + : (columnCount - _currentSprite.ColumnOffset - 1); uint8_t tileIndex = (row << 4) | ((tileColumn + columnOffset) & 0x0F); uint16_t tileStart = (_state.OamBaseAddress + (tileIndex << 4) + (useSecondTable ? _state.OamAddressOffset : 0)); _currentSprite.FetchAddress = (tileStart + yOffset) & 0x7FFF; @@ -710,7 +889,8 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) int16_t endTileX = x + ((columnCount - _currentSprite.ColumnOffset - 1) << 3) + 8; _currentSprite.DrawX = _currentSprite.X + ((columnCount - _currentSprite.ColumnOffset - 1) << 3); - if(_currentSprite.ColumnOffset == 0 || endTileX >= 256) { + if (_currentSprite.ColumnOffset == 0 || endTileX >= 256) + { //Last tile of the sprite, or skip the remaining tiles (because the tiles are hidden to the right of the screen) _spriteCount--; _currentSprite.ColumnOffset = 0; @@ -723,19 +903,25 @@ void Ppu::FetchSpriteTile(bool secondCycle) uint16_t chrData = _vram[_currentSprite.FetchAddress]; _currentSprite.ChrData[secondCycle] = chrData; - if(!secondCycle) { + if (!secondCycle) + { _currentSprite.FetchAddress = (_currentSprite.FetchAddress + 8) & 0x7FFF; - } else { + } + else + { int16_t xPos = _currentSprite.DrawX; - for(int x = 0; x < 8; x++) { - if(xPos + x < 0 || xPos + x > 255) { + for (int x = 0; x < 8; x++) + { + if (xPos + x < 0 || xPos + x > 255) + { continue; } uint8_t xOffset = _currentSprite.HorizontalMirror ? ((7 - x) & 0x07) : x; uint8_t color = GetTilePixelColor<4>(_currentSprite.ChrData, 7 - xOffset); - if(color != 0) { + if (color != 0) + { _spriteColorsCopy[xPos + x] = color; _spritePriorityCopy[xPos + x] = _currentSprite.Priority; _spritePaletteCopy[xPos + x] = _currentSprite.Palette; @@ -746,7 +932,7 @@ void Ppu::FetchSpriteTile(bool secondCycle) void Ppu::RenderMode0() { - constexpr uint8_t spritePriorities[4] = { 3, 6, 9, 12 }; + constexpr uint8_t spritePriorities[4] = {3, 6, 9, 12}; RenderSprites(spritePriorities); RenderTilemap<0, 2, 8, 11, 0>(); @@ -757,21 +943,24 @@ void Ppu::RenderMode0() void Ppu::RenderMode1() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 7, 10 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 7, 10}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 6, 9>(); RenderTilemap<1, 4, 5, 8>(); - if(!_state.Mode1Bg3Priority) { + if (!_state.Mode1Bg3Priority) + { RenderTilemap<2, 2, 1, 3>(); - } else { + } + else + { RenderTilemap<2, 2, 1, 11>(); } } void Ppu::RenderMode2() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 3, 7>(); @@ -780,7 +969,7 @@ void Ppu::RenderMode2() void Ppu::RenderMode3() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 8, 3, 7>(); @@ -789,7 +978,7 @@ void Ppu::RenderMode3() void Ppu::RenderMode4() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 8, 3, 7>(); @@ -798,7 +987,7 @@ void Ppu::RenderMode4() void Ppu::RenderMode5() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 3, 7>(); @@ -807,7 +996,7 @@ void Ppu::RenderMode5() void Ppu::RenderMode6() { - constexpr uint8_t spritePriorities[4] = { 2, 3, 4, 6 }; + constexpr uint8_t spritePriorities[4] = {2, 3, 4, 6}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 1, 5>(); @@ -815,11 +1004,12 @@ void Ppu::RenderMode6() void Ppu::RenderMode7() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 7 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 7}; RenderSprites(spritePriorities); RenderTilemapMode7<0, 3, 3>(); - if(_state.ExtBgEnabled) { + if (_state.ExtBgEnabled) + { RenderTilemapMode7<1, 1, 5>(); } } @@ -828,41 +1018,58 @@ void Ppu::RenderScanline() { int32_t hPos = GetCycle(); - if(hPos <= 255 || _spriteEvalEnd < 255) { + if (hPos <= 255 || _spriteEvalEnd < 255) + { _spriteEvalEnd = std::min(hPos, 255); - if(_spriteEvalStart <= _spriteEvalEnd) { + if (_spriteEvalStart <= _spriteEvalEnd) + { EvaluateNextLineSprites(); } _spriteEvalStart = _spriteEvalEnd + 1; } - if(!_skipRender && (hPos <= 263 || _fetchBgEnd < 263)) { + if (!_skipRender && (hPos <= 263 || _fetchBgEnd < 263)) + { //Fetch tilemap and tile CHR data, as needed, between H=0 and H=263 _fetchBgEnd = std::min(hPos, 263); - if(_fetchBgStart <= _fetchBgEnd) { + if (_fetchBgStart <= _fetchBgEnd) + { FetchTileData(); } _fetchBgStart = _fetchBgEnd + 1; - } + } //Render the scanline - if(!_skipRender && _drawStartX <= 255 && hPos > 22 && _scanline > 0) { + if (!_skipRender && _drawStartX <= 255 && hPos > 22 && _scanline > 0) + { _drawEndX = std::min(hPos - 22, 255); - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { //Forced blank, output black memset(_mainScreenBuffer + _drawStartX, 0, (_drawEndX - _drawStartX + 1) * 2); memset(_subScreenBuffer + _drawStartX, 0, (_drawEndX - _drawStartX + 1) * 2); - } else { - switch(_state.BgMode) { - case 0: RenderMode0(); break; - case 1: RenderMode1(); break; - case 2: RenderMode2(); break; - case 3: RenderMode3(); break; - case 4: RenderMode4(); break; - case 5: RenderMode5(); break; - case 6: RenderMode6(); break; - case 7: RenderMode7(); break; + } + else + { + switch (_state.BgMode) + { + case 0: RenderMode0(); + break; + case 1: RenderMode1(); + break; + case 2: RenderMode2(); + break; + case 3: RenderMode3(); + break; + case 4: RenderMode4(); + break; + case 5: RenderMode5(); + break; + case 6: RenderMode6(); + break; + case 7: RenderMode7(); + break; } RenderBgColor(); } @@ -873,12 +1080,14 @@ void Ppu::RenderScanline() _drawStartX = _drawEndX + 1; } - - if(hPos >= 270 && !_spriteFetchingDone) { + + if (hPos >= 270 && !_spriteFetchingDone) + { //Fetch sprite data from OAM and calculated which CHR data needs to be loaded (between H=270 and H=337) //Fetch sprite CHR data, as needed, between H=272 and H=339 _fetchSpriteEnd = std::min(hPos - 270, 69); - if(_fetchSpriteStart <= _fetchSpriteEnd) { + if (_fetchSpriteStart <= _fetchSpriteEnd) + { FetchSpriteData(); } _fetchSpriteStart = _fetchSpriteEnd + 1; @@ -888,12 +1097,15 @@ void Ppu::RenderScanline() void Ppu::RenderBgColor() { uint8_t pixelFlags = (_state.ColorMathEnabled & 0x20) ? PixelFlags::AllowColorMath : 0; - for(int x = _drawStartX; x <= _drawEndX; x++) { - if((_mainScreenFlags[x] & 0x0F) == 0) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if ((_mainScreenFlags[x] & 0x0F) == 0) + { _mainScreenBuffer[x] = _cgram[0]; _mainScreenFlags[x] = pixelFlags; } - if(_subScreenPriority[x] == 0) { + if (_subScreenPriority[x] == 0) + { _subScreenBuffer[x] = _cgram[0]; } } @@ -901,7 +1113,8 @@ void Ppu::RenderBgColor() void Ppu::RenderSprites(const uint8_t priority[4]) { - if(!IsRenderRequired(Ppu::SpriteLayerIndex)) { + if (!IsRenderRequired(Ppu::SpriteLayerIndex)) + { return; } @@ -910,23 +1123,35 @@ void Ppu::RenderSprites(const uint8_t priority[4]) uint8_t mainWindowCount = 0; uint8_t subWindowCount = 0; - if(_state.WindowMaskMain[Ppu::SpriteLayerIndex]) { - mainWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::SpriteLayerIndex]; + if (_state.WindowMaskMain[Ppu::SpriteLayerIndex]) + { + mainWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[Ppu::SpriteLayerIndex]; } - if(_state.WindowMaskSub[Ppu::SpriteLayerIndex]) { - subWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::SpriteLayerIndex]; + if (_state.WindowMaskSub[Ppu::SpriteLayerIndex]) + { + subWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[Ppu::SpriteLayerIndex]; } - for(int x = _drawStartX; x <= _drawEndX; x++) { - if(_spritePriority[x] <= 3) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if (_spritePriority[x] <= 3) + { uint8_t spritePrio = priority[_spritePriority[x]]; - if(drawMain && ((_mainScreenFlags[x] & 0x0F) < spritePrio) && !ProcessMaskWindow(mainWindowCount, x)) { + if (drawMain && ((_mainScreenFlags[x] & 0x0F) < spritePrio) && !ProcessMaskWindow( + mainWindowCount, x)) + { uint16_t paletteRamOffset = 128 + (_spritePalette[x] << 4) + _spriteColors[x]; _mainScreenBuffer[x] = _cgram[paletteRamOffset]; - _mainScreenFlags[x] = spritePrio | (((_state.ColorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0); + _mainScreenFlags[x] = spritePrio | (((_state.ColorMathEnabled & 0x10) && _spritePalette[x] > 3) + ? PixelFlags::AllowColorMath + : 0); } - if(drawSub && (_subScreenPriority[x] < spritePrio) && !ProcessMaskWindow(subWindowCount, x)) { + if (drawSub && (_subScreenPriority[x] < spritePrio) && !ProcessMaskWindow( + subWindowCount, x)) + { uint16_t paletteRamOffset = 128 + (_spritePalette[x] << 4) + _spriteColors[x]; _subScreenBuffer[x] = _cgram[paletteRamOffset]; _subScreenPriority[x] = spritePrio; @@ -935,19 +1160,26 @@ void Ppu::RenderSprites(const uint8_t priority[4]) } } -template +template void Ppu::RenderTilemap() { bool drawMain = (bool)(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); bool drawSub = (bool)(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); - uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; + uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; uint16_t hScrollOriginal = _state.Layers[layerIndex].HScroll; uint16_t hScroll = hiResMode ? (hScrollOriginal << 1) : hScrollOriginal; - TileData* tileData = _layerData[layerIndex].Tiles; + TileData* tileData = _layerData[layerIndex].Tiles; uint8_t mosaicCounter = applyMosaic ? _state.MosaicSize - (_drawStartX % _state.MosaicSize) : 0; @@ -956,12 +1188,16 @@ void Ppu::RenderTilemap() uint8_t hiresSubColor; uint8_t pixelFlags = (((_state.ColorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0); - for(int x = _drawStartX; x <= _drawEndX; x++) { - if(hiResMode) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if (hiResMode) + { lookupIndex = (x + (hScrollOriginal & 0x07)) >> 2; chrDataOffset = (lookupIndex & 0x01) * bpp / 2; lookupIndex >>= 1; - } else { + } + else + { lookupIndex = (x + (hScrollOriginal & 0x07)) >> 3; } @@ -970,15 +1206,18 @@ void Ppu::RenderTilemap() bool hMirror = (tilemapData & 0x4000) != 0; uint8_t color; - if(hiResMode) { + if (hiResMode) + { uint8_t xOffset = ((x << 1) + 1 + hScroll) & 0x07; uint8_t shift = hMirror ? xOffset : (7 - xOffset); color = GetTilePixelColor(chrData + chrDataOffset, shift); - + xOffset = ((x << 1) + hScroll) & 0x07; shift = hMirror ? xOffset : (7 - xOffset); hiresSubColor = GetTilePixelColor(chrData + chrDataOffset, shift); - } else { + } + else + { uint8_t xOffset = (x + hScroll) & 0x07; uint8_t shift = hMirror ? xOffset : (7 - xOffset); color = GetTilePixelColor(chrData, shift); @@ -987,86 +1226,112 @@ void Ppu::RenderTilemap() uint8_t paletteIndex = (tilemapData >> 10) & 0x07; uint8_t priority = (tilemapData & 0x2000) ? highPriority : normalPriority; - if(applyMosaic) { - if(mosaicCounter == _state.MosaicSize) { + if (applyMosaic) + { + if (mosaicCounter == _state.MosaicSize) + { mosaicCounter = 1; - if(hiResMode) { + if (hiResMode) + { color = hiresSubColor; } _mosaicColor[layerIndex] = (paletteIndex << 8) | color; _mosaicPriority[layerIndex] = priority; - } else { + } + else + { mosaicCounter++; color = _mosaicColor[layerIndex] & 0xFF; paletteIndex = _mosaicColor[layerIndex] >> 8; priority = _mosaicPriority[layerIndex]; - if(hiResMode) { + if (hiResMode) + { hiresSubColor = color; } - } + } } - if(color > 0) { + if (color > 0) + { uint16_t rgbColor = GetRgbColor(paletteIndex, color); - if(drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) { + if (drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) + { DrawMainPixel(x, rgbColor, priority | pixelFlags); } - if(!hiResMode && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { + if (!hiResMode && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow( + subWindowCount, x)) + { DrawSubPixel(x, rgbColor, priority); } } - if(hiResMode) { - if(hiresSubColor > 0 && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { - uint16_t hiresSubRgbColor = GetRgbColor(paletteIndex, hiresSubColor); + if (hiResMode) + { + if (hiresSubColor > 0 && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow( + subWindowCount, x)) + { + uint16_t hiresSubRgbColor = GetRgbColor( + paletteIndex, hiresSubColor); DrawSubPixel(x, hiresSubRgbColor, priority); } } } } -template +template uint16_t Ppu::GetRgbColor(uint8_t paletteIndex, uint8_t colorIndex) { - if(bpp == 8 && directColorMode) { + if (bpp == 8 && directColorMode) + { return ( ((((colorIndex & 0x07) << 1) | (paletteIndex & 0x01)) << 1) | (((colorIndex & 0x38) | ((paletteIndex & 0x02) << 1)) << 4) | (((colorIndex & 0xC0) | ((paletteIndex & 0x04) << 3)) << 7) ); - } else if(bpp == 8) { + } + else if (bpp == 8) + { //Ignore palette bits for 256-color layers return _cgram[basePaletteOffset + colorIndex]; - } else { + } + else + { return _cgram[basePaletteOffset + paletteIndex * (1 << bpp) + colorIndex]; } } bool Ppu::IsRenderRequired(uint8_t layerIndex) { - if(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) { + if (((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) + { return true; } - if(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) { + if (((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) + { return true; } return false; } -template +template uint8_t Ppu::GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift) { uint8_t color; - if(bpp == 2) { + if (bpp == 2) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; - } else if(bpp == 4) { + } + else if (bpp == 4) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; color |= ((chrData[1] >> shift) & 0x01) << 2; color |= ((chrData[1] >> (7 + shift)) & 0x02) << 2; - } else if(bpp == 8) { + } + else if (bpp == 8) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; color |= ((chrData[1] >> shift) & 0x01) << 2; @@ -1075,24 +1340,33 @@ uint8_t Ppu::GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift) color |= ((chrData[2] >> (7 + shift)) & 0x02) << 4; color |= ((chrData[3] >> shift) & 0x01) << 6; color |= ((chrData[3] >> (7 + shift)) & 0x02) << 6; - } else { + } + else + { throw std::runtime_error("unsupported bpp"); } return color; } -template +template void Ppu::RenderTilemapMode7() { - uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - + uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + bool drawMain = (bool)(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); bool drawSub = (bool)(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); auto clip = [](int32_t val) { return (val & 0x2000) ? (val | ~0x3ff) : (val & 0x3ff); }; - if(_drawStartX == 0) { + if (_drawStartX == 0) + { //Keep the same scroll offsets for the entire scanline _state.Mode7.HScrollLatch = _state.Mode7.HScroll; _state.Mode7.VScrollLatch = _state.Mode7.VScroll; @@ -1104,7 +1378,8 @@ void Ppu::RenderTilemapMode7() int32_t centerY = ((int32_t)_state.Mode7.CenterY << 19) >> 19; uint16_t realY = _state.Mode7.VerticalMirroring ? (255 - _scanline) : _scanline; - if(applyMosaic) { + if (applyMosaic) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; } @@ -1126,7 +1401,8 @@ void Ppu::RenderTilemapMode7() int16_t xStep = _state.Mode7.Matrix[0]; int16_t yStep = _state.Mode7.Matrix[2]; - if(_state.Mode7.HorizontalMirroring) { + if (_state.Mode7.HorizontalMirroring) + { //Calculate the value at the end of the scanline, and then start going backwards xValue += xStep * _drawEndX; yValue += yStep * _drawEndX; @@ -1136,69 +1412,92 @@ void Ppu::RenderTilemapMode7() xValue += xStep * _drawStartX; yValue += yStep * _drawStartX; - + uint8_t pixelFlags = ((_state.ColorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0; - for(int x = _drawStartX; x <= _drawEndX; x++) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { int32_t xOffset = xValue >> 8; int32_t yOffset = yValue >> 8; xValue += xStep; yValue += yStep; uint8_t tileIndex; - if(!_state.Mode7.LargeMap) { + if (!_state.Mode7.LargeMap) + { yOffset &= 0x3FF; xOffset &= 0x3FF; tileIndex = (uint8_t)_vram[((yOffset & ~0x07) << 4) | (xOffset >> 3)]; - } else { - if(yOffset < 0 || yOffset > 0x3FF || xOffset < 0 || xOffset > 0x3FF) { - if(_state.Mode7.FillWithTile0) { + } + else + { + if (yOffset < 0 || yOffset > 0x3FF || xOffset < 0 || xOffset > 0x3FF) + { + if (_state.Mode7.FillWithTile0) + { tileIndex = 0; - } else { + } + else + { //Draw nothing for this pixel, we're outside the map continue; } - } else { + } + else + { tileIndex = (uint8_t)_vram[((yOffset & ~0x07) << 4) | (xOffset >> 3)]; } } uint16_t colorIndex; uint8_t priority; - if(layerIndex == 1) { + if (layerIndex == 1) + { uint8_t color = _vram[((tileIndex << 6) + ((yOffset & 0x07) << 3) + (xOffset & 0x07))] >> 8; priority = (color & 0x80) ? highPriority : normalPriority; colorIndex = (color & 0x7F); - } else { + } + else + { priority = normalPriority; colorIndex = _vram[((tileIndex << 6) + ((yOffset & 0x07) << 3) + (xOffset & 0x07))] >> 8; } - if(applyMosaic) { - if(mosaicCounter == _state.MosaicSize) { + if (applyMosaic) + { + if (mosaicCounter == _state.MosaicSize) + { mosaicCounter = 1; _mosaicColor[layerIndex] = colorIndex; _mosaicPriority[layerIndex] = priority; - } else { + } + else + { mosaicCounter++; colorIndex = _mosaicColor[layerIndex]; priority = _mosaicPriority[layerIndex]; } } - if(colorIndex > 0) { + if (colorIndex > 0) + { uint16_t paletteColor; - if(directColorMode) { + if (directColorMode) + { paletteColor = ((colorIndex & 0x07) << 2) | ((colorIndex & 0x38) << 4) | ((colorIndex & 0xC0) << 7); - } else { + } + else + { paletteColor = _cgram[colorIndex]; } - - if(drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) { - DrawMainPixel(x, paletteColor, priority | pixelFlags); - } - if(drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { + if (drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) + { + DrawMainPixel(x, paletteColor, priority | pixelFlags); + } + + if (drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) + { DrawSubPixel(x, paletteColor, priority); } } @@ -1219,11 +1518,14 @@ void Ppu::DrawSubPixel(uint8_t x, uint16_t color, uint8_t priority) void Ppu::ApplyColorMath() { - uint8_t activeWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::ColorWindowIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::ColorWindowIndex]; + uint8_t activeWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::ColorWindowIndex] + (uint8_t)_state.Window[1] + .ActiveLayers[Ppu::ColorWindowIndex]; bool hiResMode = _state.HiResMode || _state.BgMode == 5 || _state.BgMode == 6; - if(hiResMode) { - for(int x = _drawStartX; x <= _drawEndX; x++) { + if (hiResMode) + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { bool isInsideWindow = ProcessMaskWindow(activeWindowCount, x); //Keep original subscreen color, which is used to apply color math to the main screen after @@ -1235,86 +1537,106 @@ void Ppu::ApplyColorMath() ApplyColorMathToPixel(_mainScreenBuffer[x], subPixel, x, isInsideWindow); } - } else { - for(int x = _drawStartX; x <= _drawEndX; x++) { + } + else + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { bool isInsideWindow = ProcessMaskWindow(activeWindowCount, x); ApplyColorMathToPixel(_mainScreenBuffer[x], _subScreenBuffer[x], x, isInsideWindow); } } } -void Ppu::ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool isInsideWindow) +void Ppu::ApplyColorMathToPixel(uint16_t& pixelA, uint16_t pixelB, int x, bool isInsideWindow) { uint8_t halfShift = (uint8_t)_state.ColorMathHalveResult; //Set color to black as needed based on clip mode - switch(_state.ColorMathClipMode) { - default: - case ColorWindowMode::Never: break; + switch (_state.ColorMathClipMode) + { + default: + case ColorWindowMode::Never: break; - case ColorWindowMode::OutsideWindow: - if(!isInsideWindow) { - pixelA = 0; - halfShift = 0; - } - break; + case ColorWindowMode::OutsideWindow: + if (!isInsideWindow) + { + pixelA = 0; + halfShift = 0; + } + break; - case ColorWindowMode::InsideWindow: - if(isInsideWindow) { - pixelA = 0; - halfShift = 0; - } - break; + case ColorWindowMode::InsideWindow: + if (isInsideWindow) + { + pixelA = 0; + halfShift = 0; + } + break; - case ColorWindowMode::Always: pixelA = 0; break; + case ColorWindowMode::Always: pixelA = 0; + break; } - if(!(_mainScreenFlags[x] & PixelFlags::AllowColorMath)) { + if (!(_mainScreenFlags[x] & PixelFlags::AllowColorMath)) + { //Color math doesn't apply to this pixel return; } //Prevent color math as needed based on mode - switch(_state.ColorMathPreventMode) { - default: - case ColorWindowMode::Never: break; + switch (_state.ColorMathPreventMode) + { + default: + case ColorWindowMode::Never: break; - case ColorWindowMode::OutsideWindow: - if(!isInsideWindow) { - return; - } - break; + case ColorWindowMode::OutsideWindow: + if (!isInsideWindow) + { + return; + } + break; - case ColorWindowMode::InsideWindow: - if(isInsideWindow) { - return; - } - break; + case ColorWindowMode::InsideWindow: + if (isInsideWindow) + { + return; + } + break; - case ColorWindowMode::Always: return; + case ColorWindowMode::Always: return; } uint16_t otherPixel; - if(_state.ColorMathAddSubscreen) { - if(_subScreenPriority[x] > 0) { + if (_state.ColorMathAddSubscreen) + { + if (_subScreenPriority[x] > 0) + { otherPixel = pixelB; - } else { + } + else + { //there's nothing in the subscreen at this pixel, use the fixed color and disable halve operation otherPixel = _state.FixedColor; halfShift = 0; } - } else { + } + else + { otherPixel = _state.FixedColor; } constexpr unsigned int mask = 0x1F; - if(_state.ColorMathSubstractMode) { + if (_state.ColorMathSubstractMode) + { uint16_t r = std::max((int)((pixelA & mask) - (otherPixel & mask)), 0) >> halfShift; uint16_t g = std::max((int)(((pixelA >> 5U) & mask) - ((otherPixel >> 5U) & mask)), 0) >> halfShift; uint16_t b = std::max((int)(((pixelA >> 10U) & mask) - ((otherPixel >> 10U) & mask)), 0) >> halfShift; pixelA = r | (g << 5U) | (b << 10U); - } else { + } + else + { uint16_t r = std::min(((pixelA & mask) + (otherPixel & mask)) >> halfShift, mask); uint16_t g = std::min((((pixelA >> 5U) & mask) + ((otherPixel >> 5U) & mask)) >> halfShift, mask); uint16_t b = std::min((((pixelA >> 10U) & mask) + ((otherPixel >> 10U) & mask)) >> halfShift, mask); @@ -1323,12 +1645,14 @@ void Ppu::ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool i } } -template +template void Ppu::ApplyBrightness() { - if(_state.ScreenBrightness != 15) { - for(int x = _drawStartX; x <= _drawEndX; x++) { - uint16_t &pixel = (forMainScreen ? _mainScreenBuffer : _subScreenBuffer)[x]; + if (_state.ScreenBrightness != 15) + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + uint16_t& pixel = (forMainScreen ? _mainScreenBuffer : _subScreenBuffer)[x]; uint16_t r = (pixel & 0x1F) * _state.ScreenBrightness / 15; uint16_t g = ((pixel >> 5) & 0x1F) * _state.ScreenBrightness / 15; uint16_t b = ((pixel >> 10) & 0x1F) * _state.ScreenBrightness / 15; @@ -1340,7 +1664,9 @@ void Ppu::ApplyBrightness() void Ppu::ConvertToHiRes() { bool useHighResOutput = _useHighResOutput || IsDoubleWidth() || _state.ScreenInterlace; - if(!useHighResOutput || _useHighResOutput == useHighResOutput || _scanline >= _vblankStartScanline || _scanline == 0) { + if (!useHighResOutput || _useHighResOutput == useHighResOutput || _scanline >= _vblankStartScanline || _scanline == 0 + ) + { return; } @@ -1349,16 +1675,20 @@ void Ppu::ConvertToHiRes() uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6); - if(_drawStartX > 0) { - for(int x = 0; x < _drawStartX; x++) { + if (_drawStartX > 0) + { + for (int x = 0; x < _drawStartX; x++) + { _currentBuffer[(scanline << 10) + (x << 1)] = _currentBuffer[(scanline << 8) + x]; _currentBuffer[(scanline << 10) + (x << 1) + 1] = _currentBuffer[(scanline << 8) + x]; } memcpy(_currentBuffer + (scanline << 10) + 512, _currentBuffer + (scanline << 10), 512 * sizeof(uint16_t)); } - for(int i = scanline - 1; i >= 0; i--) { - for(int x = 0; x < 256; x++) { + for (int i = scanline - 1; i >= 0; i--) + { + for (int x = 0; x < 256; x++) + { _currentBuffer[(i << 10) + (x << 1)] = _currentBuffer[(i << 8) + x]; _currentBuffer[(i << 10) + (x << 1) + 1] = _currentBuffer[(i << 8) + x]; } @@ -1371,27 +1701,39 @@ void Ppu::ApplyHiResMode() //When overscan mode is off, center the 224-line picture in the center of the 239-line output buffer uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6); - if(!_useHighResOutput) { - memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, (_drawEndX - _drawStartX + 1) << 1); - } else { + if (!_useHighResOutput) + { + memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, + (_drawEndX - _drawStartX + 1) << 1); + } + else + { _interlacedFrame |= _state.ScreenInterlace; - uint32_t screenY = _state.ScreenInterlace ? (_oddFrame ? ((scanline << 1) + 1) : (scanline << 1)) : (scanline << 1); + uint32_t screenY = _state.ScreenInterlace + ? (_oddFrame ? ((scanline << 1) + 1) : (scanline << 1)) + : (scanline << 1); uint32_t baseAddr = (screenY << 9); - if(IsDoubleWidth()) { + if (IsDoubleWidth()) + { ApplyBrightness(); - for(int x = _drawStartX; x <= _drawEndX; x++) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { _currentBuffer[baseAddr + (x << 1)] = _subScreenBuffer[x]; _currentBuffer[baseAddr + (x << 1) + 1] = _mainScreenBuffer[x]; } - } else { - for(int x = _drawStartX; x <= _drawEndX; x++) { + } + else + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { _currentBuffer[baseAddr + (x << 1)] = _mainScreenBuffer[x]; _currentBuffer[baseAddr + (x << 1) + 1] = _mainScreenBuffer[x]; } } - if(!_state.ScreenInterlace) { + if (!_state.ScreenInterlace) + { //Copy this line's content to the next line (between the current start & end bounds) memcpy( _currentBuffer + baseAddr + 512 + (_drawStartX << 1), @@ -1402,24 +1744,31 @@ void Ppu::ApplyHiResMode() } } -template +template bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x) { - switch(activeWindowCount) { - case 1: - if(_state.Window[0].ActiveLayers[layerIndex]) { - return _state.Window[0].PixelNeedsMasking(x); - } - return _state.Window[1].PixelNeedsMasking(x); + switch (activeWindowCount) + { + case 1: + if (_state.Window[0].ActiveLayers[layerIndex]) + { + return _state.Window[0].PixelNeedsMasking(x); + } + return _state.Window[1].PixelNeedsMasking(x); - case 2: - switch(_state.MaskLogic[layerIndex]) { - default: - case WindowMaskLogic::Or: return _state.Window[0].PixelNeedsMasking(x) | _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::And: return _state.Window[0].PixelNeedsMasking(x) & _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::Xor: return _state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::Xnor: return !(_state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1].PixelNeedsMasking(x)); - } + case 2: + switch (_state.MaskLogic[layerIndex]) + { + default: + case WindowMaskLogic::Or: return _state.Window[0].PixelNeedsMasking(x) | _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::And: return _state.Window[0].PixelNeedsMasking(x) & _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::Xor: return _state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::Xnor: return !(_state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1]. + PixelNeedsMasking(x)); + } } return false; } @@ -1442,7 +1791,8 @@ void Ppu::SendFrame() uint16_t width = _useHighResOutput ? 512 : 256; uint16_t height = _useHighResOutput ? 478 : 239; - if(!_overscanFrame) { + if (!_overscanFrame) + { //Clear the top 7 and bottom 8 rows int top = (_useHighResOutput ? 14 : 7); int bottom = (_useHighResOutput ? 16 : 8); @@ -1457,14 +1807,18 @@ void Ppu::SendFrame() #ifdef LIBRETRO _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding); #else - if(isRewinding || _interlacedFrame) { + if (isRewinding || _interlacedFrame) + { _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding); - } else { + } + else + { _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, width, height, _frameCount); } #endif - if(!_skipRender) { + if (!_skipRender) + { _frameSkipTimer.Reset(); } } @@ -1521,10 +1875,12 @@ void Ppu::SetLocationLatchRequest(uint16_t x, uint16_t y) void Ppu::ProcessLocationLatchRequest() { //Used by super scope - if(_latchRequest) { + if (_latchRequest) + { uint16_t cycle = GetCycle(); uint16_t scanline = GetRealScanline(); - if(scanline > _latchRequestY || (_latchRequestY == scanline && cycle >= _latchRequestX)) { + if (scanline > _latchRequestY || (_latchRequestY == scanline && cycle >= _latchRequestX)) + { _latchRequest = false; _horizontalLocation = _latchRequestX; _verticalLocation = _latchRequestY; @@ -1547,12 +1903,18 @@ void Ppu::UpdateOamAddress() uint16_t Ppu::GetOamAddress() { - if(_state.ForcedVblank || _scanline >= _vblankStartScanline) { + if (_state.ForcedVblank || _scanline >= _vblankStartScanline) + { return _internalOamAddress; - } else { - if(_memoryManager->GetHClock() <= 255 * 4) { + } + else + { + if (_memoryManager->GetHClock() <= 255 * 4) + { return _oamEvaluationIndex << 2; - } else { + } + else + { return _oamTimeIndex << 2; } } @@ -1567,66 +1929,76 @@ void Ppu::UpdateVramReadBuffer() uint16_t Ppu::GetVramAddress() { uint16_t addr = _state.VramAddress; - switch(_state.VramAddressRemapping) { - default: - case 0: return addr; - case 1: return (addr & 0xFF00) | ((addr & 0xE0) >> 5) | ((addr & 0x1F) << 3); - case 2: return (addr & 0xFE00) | ((addr & 0x1C0) >> 6) | ((addr & 0x3F) << 3); - case 3: return (addr & 0xFC00) | ((addr & 0x380) >> 7) | ((addr & 0x7F) << 3); + switch (_state.VramAddressRemapping) + { + default: + case 0: return addr; + case 1: return (addr & 0xFF00) | ((addr & 0xE0) >> 5) | ((addr & 0x1F) << 3); + case 2: return (addr & 0xFE00) | ((addr & 0x1C0) >> 6) | ((addr & 0x3F) << 3); + case 3: return (addr & 0xFC00) | ((addr & 0x380) >> 7) | ((addr & 0x7F) << 3); } } uint8_t Ppu::Read(uint16_t addr) { - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); } - switch(addr) { - case 0x2134: - _state.Ppu1OpenBus = ((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) & 0xFF; - return _state.Ppu1OpenBus; + switch (addr) + { + case 0x2134: + _state.Ppu1OpenBus = ((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2135: - _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 8) & 0xFF; - return _state.Ppu1OpenBus; + case 0x2135: + _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 8) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2136: - _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 16) & 0xFF; - return _state.Ppu1OpenBus; + case 0x2136: + _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 16) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2137: - //SLHV - Software Latch for H/V Counter - //Latch values on read, and return open bus - if(_regs->GetIoPortOutput() & 0x80) { - //Only latch H/V counters if bit 7 of $4201 is set. - LatchLocationValues(); - } - break; - - case 0x2138: { + case 0x2137: + //SLHV - Software Latch for H/V Counter + //Latch values on read, and return open bus + if (_regs->GetIoPortOutput() & 0x80) + { + //Only latch H/V counters if bit 7 of $4201 is set. + LatchLocationValues(); + } + break; + + case 0x2138: + { //OAMDATAREAD - Data for OAM read //When trying to read/write during rendering, the internal address used by the PPU's sprite rendering is used uint16_t oamAddr = GetOamAddress(); uint8_t value; - if(oamAddr < 512) { + if (oamAddr < 512) + { value = _oamRam[oamAddr]; _console->ProcessPpuRead(oamAddr, value, SnesMemoryType::SpriteRam); - } else { + } + else + { value = _oamRam[0x200 | (oamAddr & 0x1F)]; _console->ProcessPpuRead(0x200 | (oamAddr & 0x1F), value, SnesMemoryType::SpriteRam); } - + _internalOamAddress = (_internalOamAddress + 1) & 0x3FF; _state.Ppu1OpenBus = value; return value; } - case 0x2139: { + case 0x2139: + { //VMDATALREAD - VRAM Data Read low byte uint8_t returnValue = (uint8_t)_state.VramReadBuffer; _console->ProcessPpuRead(GetVramAddress(), returnValue, SnesMemoryType::VideoRam); - if(!_state.VramAddrIncrementOnSecondReg) { + if (!_state.VramAddrIncrementOnSecondReg) + { UpdateVramReadBuffer(); _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; } @@ -1634,11 +2006,13 @@ uint8_t Ppu::Read(uint16_t addr) return returnValue; } - case 0x213A: { + case 0x213A: + { //VMDATAHREAD - VRAM Data Read high byte uint8_t returnValue = (uint8_t)(_state.VramReadBuffer >> 8); _console->ProcessPpuRead(GetVramAddress() + 1, returnValue, SnesMemoryType::VideoRam); - if(_state.VramAddrIncrementOnSecondReg) { + if (_state.VramAddrIncrementOnSecondReg) + { UpdateVramReadBuffer(); _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; } @@ -1646,33 +2020,41 @@ uint8_t Ppu::Read(uint16_t addr) return returnValue; } - case 0x213B: { + case 0x213B: + { //CGDATAREAD - CGRAM Data read uint8_t value; - if(_state.CgramAddressLatch){ + if (_state.CgramAddressLatch) + { value = ((_cgram[_state.CgramAddress] >> 8) & 0x7F) | (_state.Ppu2OpenBus & 0x80); _state.CgramAddress++; - + _console->ProcessPpuRead((_state.CgramAddress >> 1) + 1, value, SnesMemoryType::CGRam); - } else { + } + else + { value = (uint8_t)_cgram[_state.CgramAddress]; _console->ProcessPpuRead(_state.CgramAddress >> 1, value, SnesMemoryType::CGRam); } _state.CgramAddressLatch = !_state.CgramAddressLatch; - + _state.Ppu2OpenBus = value; return value; } - case 0x213C: { + case 0x213C: + { //OPHCT - Horizontal Scanline Location ProcessLocationLatchRequest(); uint8_t value; - if(_horizontalLocToggle) { + if (_horizontalLocToggle) + { //"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus." value = ((_horizontalLocation & 0x100) >> 8) | (_state.Ppu2OpenBus & 0xFE); - } else { + } + else + { value = _horizontalLocation & 0xFF; } _state.Ppu2OpenBus = value; @@ -1680,15 +2062,19 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213D: { + case 0x213D: + { //OPVCT - Vertical Scanline Location ProcessLocationLatchRequest(); uint8_t value; - if(_verticalLocationToggle) { + if (_verticalLocationToggle) + { //"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus." value = ((_verticalLocation & 0x100) >> 8) | (_state.Ppu2OpenBus & 0xFE); - } else { + } + else + { value = _verticalLocation & 0xFF; } _state.Ppu2OpenBus = value; @@ -1696,7 +2082,8 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213E: { + case 0x213E: + { //STAT77 - PPU Status Flag and Version uint8_t value = ( (_timeOver ? 0x80 : 0) | @@ -1708,7 +2095,8 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213F: { + case 0x213F: + { //STAT78 - PPU Status Flag and Version ProcessLocationLatchRequest(); @@ -1720,7 +2108,8 @@ uint8_t Ppu::Read(uint16_t addr) 0x03 //PPU (5c78) chip version ); - if(_regs->GetIoPortOutput() & 0x80) { + if (_regs->GetIoPortOutput() & 0x80) + { _locationLatched = false; //"The high/low selector is reset to ?elow?f when $213F is read" (the selector is NOT reset when the counter is latched) @@ -1731,13 +2120,14 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - default: - LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); - break; + default: + LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); + break; } - + uint16_t reg = addr & 0x210F; - if((reg >= 0x2104 && reg <= 0x2106) || (reg >= 0x2108 && reg <= 0x210A)) { + if ((reg >= 0x2104 && reg <= 0x2106) || (reg >= 0x2108 && reg <= 0x210A)) + { //Registers matching $21x4-6 or $21x8-A (where x is 0-2) return the last value read from any of the PPU1 registers $2134-6, $2138-A, or $213E. return _state.Ppu1OpenBus; } @@ -1746,63 +2136,74 @@ uint8_t Ppu::Read(uint16_t addr) void Ppu::Write(uint32_t addr, uint8_t value) { - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); } - switch(addr) { - case 0x2100: - if(_state.ForcedVblank && _scanline == _nmiScanline) { - //"writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur." - UpdateOamAddress(); - } - - _state.ForcedVblank = (value & 0x80) != 0; - _state.ScreenBrightness = value & 0x0F; - break; - - case 0x2101: - _state.OamMode = (value & 0xE0) >> 5; - _state.OamBaseAddress = (value & 0x07) << 13; - _state.OamAddressOffset = (((value & 0x18) >> 3) + 1) << 12; - break; - - case 0x2102: - _state.OamRamAddress = (_state.OamRamAddress & 0x100) | value; + switch (addr) + { + case 0x2100: + if (_state.ForcedVblank && _scanline == _nmiScanline) + { + //"writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur." UpdateOamAddress(); - break; + } - case 0x2103: - _state.OamRamAddress = (_state.OamRamAddress & 0xFF) | ((value & 0x01) << 8); - UpdateOamAddress(); - _state.EnableOamPriority = (value & 0x80) != 0; - break; + _state.ForcedVblank = (value & 0x80) != 0; + _state.ScreenBrightness = value & 0x0F; + break; - case 0x2104: { + case 0x2101: + _state.OamMode = (value & 0xE0) >> 5; + _state.OamBaseAddress = (value & 0x07) << 13; + _state.OamAddressOffset = (((value & 0x18) >> 3) + 1) << 12; + break; + + case 0x2102: + _state.OamRamAddress = (_state.OamRamAddress & 0x100) | value; + UpdateOamAddress(); + break; + + case 0x2103: + _state.OamRamAddress = (_state.OamRamAddress & 0xFF) | ((value & 0x01) << 8); + UpdateOamAddress(); + _state.EnableOamPriority = (value & 0x80) != 0; + break; + + case 0x2104: + { //When trying to read/write during rendering, the internal address used by the PPU's sprite rendering is used //This is approximated by _oamRenderAddress (but is not cycle accurate) - needed for Uniracers uint16_t oamAddr = GetOamAddress(); - - if(oamAddr < 512) { - if(oamAddr & 0x01) { + + if (oamAddr < 512) + { + if (oamAddr & 0x01) + { _console->ProcessPpuWrite(oamAddr - 1, _oamWriteBuffer, SnesMemoryType::SpriteRam); _oamRam[oamAddr - 1] = _oamWriteBuffer; - + _console->ProcessPpuWrite(oamAddr, value, SnesMemoryType::SpriteRam); _oamRam[oamAddr] = value; - } else { + } + else + { _oamWriteBuffer = value; } - } + } - if(!_state.ForcedVblank && _scanline < _nmiScanline) { + if (!_state.ForcedVblank && _scanline < _nmiScanline) + { //During rendering the high table is also written to when writing to OAM oamAddr = 0x200 | ((oamAddr & 0x1F0) >> 4); } - - if(oamAddr >= 512) { + + if (oamAddr >= 512) + { uint16_t address = 0x200 | (oamAddr & 0x1F); - if((oamAddr & 0x01) == 0) { + if ((oamAddr & 0x01) == 0) + { _oamWriteBuffer = value; } _console->ProcessPpuWrite(address, value, SnesMemoryType::SpriteRam); @@ -1812,26 +2213,30 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - case 0x2105: - if(_state.BgMode != (value & 0x07)) { - LogDebug("[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")"); - } - _state.BgMode = value & 0x07; - ConvertToHiRes(); + case 0x2105: + if (_state.BgMode != (value & 0x07)) + { + LogDebug( + "[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")"); + } + _state.BgMode = value & 0x07; + ConvertToHiRes(); - _state.Mode1Bg3Priority = (value & 0x08) != 0; + _state.Mode1Bg3Priority = (value & 0x08) != 0; - _state.Layers[0].LargeTiles = (value & 0x10) != 0; - _state.Layers[1].LargeTiles = (value & 0x20) != 0; - _state.Layers[2].LargeTiles = (value & 0x40) != 0; - _state.Layers[3].LargeTiles = (value & 0x80) != 0; - break; + _state.Layers[0].LargeTiles = (value & 0x10) != 0; + _state.Layers[1].LargeTiles = (value & 0x20) != 0; + _state.Layers[2].LargeTiles = (value & 0x40) != 0; + _state.Layers[3].LargeTiles = (value & 0x80) != 0; + break; - case 0x2106: { + case 0x2106: + { //MOSAIC - Screen Pixelation _state.MosaicSize = ((value & 0xF0) >> 4) + 1; uint8_t mosaicEnabled = value & 0x0F; - if(!_state.MosaicEnabled && mosaicEnabled) { + if (!_state.MosaicEnabled && mosaicEnabled) + { //"If this register is set during the frame, the ?starting scanline is the current scanline, otherwise it is the first visible scanline of the frame." //This is only done when mosaic is turned on from an off state (FF6 mosaic effect looks wrong otherwise) //FF6's mosaic effect is broken on some screens without this. @@ -1841,249 +2246,281 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - case 0x2107: case 0x2108: case 0x2109: case 0x210A: - //BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC) - _state.Layers[addr - 0x2107].TilemapAddress = (value & 0x7C) << 8; - _state.Layers[addr - 0x2107].DoubleWidth = (value & 0x01) != 0; - _state.Layers[addr - 0x2107].DoubleHeight = (value & 0x02) != 0; + case 0x2107: + case 0x2108: + case 0x2109: + case 0x210A: + //BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC) + _state.Layers[addr - 0x2107].TilemapAddress = (value & 0x7C) << 8; + _state.Layers[addr - 0x2107].DoubleWidth = (value & 0x01) != 0; + _state.Layers[addr - 0x2107].DoubleHeight = (value & 0x02) != 0; + break; + + case 0x210B: + case 0x210C: + //BG1+2 / BG3+4 Chr Address (BG12NBA / BG34NBA) + _state.Layers[(addr - 0x210B) * 2].ChrAddress = (value & 0x07) << 12; + _state.Layers[(addr - 0x210B) * 2 + 1].ChrAddress = (value & 0x70) << 8; + break; + + case 0x210D: + //M7HOFS - Mode 7 BG Horizontal Scroll + //BG1HOFS - BG1 Horizontal Scroll + _state.Mode7.HScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; + _state.Mode7.ValueLatch = value; + //no break, keep executing to set the matching BG1 HScroll register, too + + case 0x210F: + case 0x2111: + case 0x2113: + //BGXHOFS - BG1/2/3/4 Horizontal Scroll + _state.Layers[(addr - 0x210D) >> 1].HScroll = ((value << 8) | (_hvScrollLatchValue & ~0x07) | (_hScrollLatchValue + & 0x07)) & 0x3FF; + _hvScrollLatchValue = value; + _hScrollLatchValue = value; + break; + + case 0x210E: + //M7VOFS - Mode 7 BG Vertical Scroll + //BG1VOFS - BG1 Vertical Scroll + _state.Mode7.VScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; + _state.Mode7.ValueLatch = value; + //no break, keep executing to set the matching BG1 HScroll register, too + + case 0x2110: + case 0x2112: + case 0x2114: + //BGXVOFS - BG1/2/3/4 Vertical Scroll + _state.Layers[(addr - 0x210E) >> 1].VScroll = ((value << 8) | _hvScrollLatchValue) & 0x3FF; + _hvScrollLatchValue = value; + break; + + case 0x2115: + //VMAIN - Video Port Control + switch (value & 0x03) + { + case 0: _state.VramIncrementValue = 1; + break; + case 1: _state.VramIncrementValue = 32; break; - case 0x210B: case 0x210C: - //BG1+2 / BG3+4 Chr Address (BG12NBA / BG34NBA) - _state.Layers[(addr - 0x210B) * 2].ChrAddress = (value & 0x07) << 12; - _state.Layers[(addr - 0x210B) * 2 + 1].ChrAddress = (value & 0x70) << 8; + case 2: + case 3: _state.VramIncrementValue = 128; break; - - case 0x210D: - //M7HOFS - Mode 7 BG Horizontal Scroll - //BG1HOFS - BG1 Horizontal Scroll - _state.Mode7.HScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; - _state.Mode7.ValueLatch = value; - //no break, keep executing to set the matching BG1 HScroll register, too + } - case 0x210F: case 0x2111: case 0x2113: - //BGXHOFS - BG1/2/3/4 Horizontal Scroll - _state.Layers[(addr - 0x210D) >> 1].HScroll = ((value << 8) | (_hvScrollLatchValue & ~0x07) | (_hScrollLatchValue & 0x07)) & 0x3FF; - _hvScrollLatchValue = value; - _hScrollLatchValue = value; - break; + _state.VramAddressRemapping = (value & 0x0C) >> 2; + _state.VramAddrIncrementOnSecondReg = (value & 0x80) != 0; + break; - case 0x210E: - //M7VOFS - Mode 7 BG Vertical Scroll - //BG1VOFS - BG1 Vertical Scroll - _state.Mode7.VScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; - _state.Mode7.ValueLatch = value; - //no break, keep executing to set the matching BG1 HScroll register, too + case 0x2116: + //VMADDL - VRAM Address low byte + _state.VramAddress = (_state.VramAddress & 0x7F00) | value; + UpdateVramReadBuffer(); + break; - case 0x2110: case 0x2112: case 0x2114: - //BGXVOFS - BG1/2/3/4 Vertical Scroll - _state.Layers[(addr - 0x210E) >> 1].VScroll = ((value << 8) | _hvScrollLatchValue) & 0x3FF; - _hvScrollLatchValue = value; - break; + case 0x2117: + //VMADDH - VRAM Address high byte + _state.VramAddress = (_state.VramAddress & 0x00FF) | ((value & 0x7F) << 8); + UpdateVramReadBuffer(); + break; - case 0x2115: - //VMAIN - Video Port Control - switch(value & 0x03) { - case 0: _state.VramIncrementValue = 1; break; - case 1: _state.VramIncrementValue = 32; break; - - case 2: - case 3: _state.VramIncrementValue = 128; break; - } + case 0x2118: + //VMDATAL - VRAM Data Write low byte + if (_scanline >= _nmiScanline || _state.ForcedVblank) + { + //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) + _console->ProcessPpuWrite(GetVramAddress() << 1, value, SnesMemoryType::VideoRam); + _vram[GetVramAddress()] = value | (_vram[GetVramAddress()] & 0xFF00); + } - _state.VramAddressRemapping = (value & 0x0C) >> 2; - _state.VramAddrIncrementOnSecondReg = (value & 0x80) != 0; - break; + //The VRAM address is incremented even outside of vblank/forced blank + if (!_state.VramAddrIncrementOnSecondReg) + { + _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; + } + break; - case 0x2116: - //VMADDL - VRAM Address low byte - _state.VramAddress = (_state.VramAddress & 0x7F00) | value; - UpdateVramReadBuffer(); - break; + case 0x2119: + //VMDATAH - VRAM Data Write high byte + if (_scanline >= _nmiScanline || _state.ForcedVblank) + { + //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) + _console->ProcessPpuWrite((GetVramAddress() << 1) + 1, value, SnesMemoryType::VideoRam); + _vram[GetVramAddress()] = (value << 8) | (_vram[GetVramAddress()] & 0xFF); + } - case 0x2117: - //VMADDH - VRAM Address high byte - _state.VramAddress = (_state.VramAddress & 0x00FF) | ((value & 0x7F) << 8); - UpdateVramReadBuffer(); - break; + //The VRAM address is incremented even outside of vblank/forced blank + if (_state.VramAddrIncrementOnSecondReg) + { + _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; + } + break; - case 0x2118: - //VMDATAL - VRAM Data Write low byte - if(_scanline >= _nmiScanline || _state.ForcedVblank) { - //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) - _console->ProcessPpuWrite(GetVramAddress() << 1, value, SnesMemoryType::VideoRam); - _vram[GetVramAddress()] = value | (_vram[GetVramAddress()] & 0xFF00); - } + case 0x211A: + //M7SEL - Mode 7 Settings + _state.Mode7.LargeMap = (value & 0x80) != 0; + _state.Mode7.FillWithTile0 = (value & 0x40) != 0; + _state.Mode7.HorizontalMirroring = (value & 0x01) != 0; + _state.Mode7.VerticalMirroring = (value & 0x02) != 0; + break; - //The VRAM address is incremented even outside of vblank/forced blank - if(!_state.VramAddrIncrementOnSecondReg) { - _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; - } - break; + case 0x211B: + case 0x211C: + case 0x211D: + case 0x211E: + //M7A/B/C/D - Mode 7 Matrix A/B/C/D (A/B are also used with $2134/6) + _state.Mode7.Matrix[addr - 0x211B] = (value << 8) | _state.Mode7.ValueLatch; + _state.Mode7.ValueLatch = value; + break; - case 0x2119: - //VMDATAH - VRAM Data Write high byte - if(_scanline >= _nmiScanline || _state.ForcedVblank) { - //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) - _console->ProcessPpuWrite((GetVramAddress() << 1) + 1, value, SnesMemoryType::VideoRam); - _vram[GetVramAddress()] = (value << 8) | (_vram[GetVramAddress()] & 0xFF); - } - - //The VRAM address is incremented even outside of vblank/forced blank - if(_state.VramAddrIncrementOnSecondReg) { - _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; - } - break; + case 0x211F: + //M7X - Mode 7 Center X + _state.Mode7.CenterX = ((value << 8) | _state.Mode7.ValueLatch); + _state.Mode7.ValueLatch = value; + break; - case 0x211A: - //M7SEL - Mode 7 Settings - _state.Mode7.LargeMap = (value & 0x80) != 0; - _state.Mode7.FillWithTile0 = (value & 0x40) != 0; - _state.Mode7.HorizontalMirroring = (value & 0x01) != 0; - _state.Mode7.VerticalMirroring = (value & 0x02) != 0; - break; + case 0x2120: + //M7Y - Mode 7 Center Y + _state.Mode7.CenterY = ((value << 8) | _state.Mode7.ValueLatch); + _state.Mode7.ValueLatch = value; + break; - case 0x211B: case 0x211C: case 0x211D: case 0x211E: - //M7A/B/C/D - Mode 7 Matrix A/B/C/D (A/B are also used with $2134/6) - _state.Mode7.Matrix[addr - 0x211B] = (value << 8) | _state.Mode7.ValueLatch; - _state.Mode7.ValueLatch = value; - break; - - case 0x211F: - //M7X - Mode 7 Center X - _state.Mode7.CenterX = ((value << 8) | _state.Mode7.ValueLatch); - _state.Mode7.ValueLatch = value; - break; + case 0x2121: + //CGRAM Address(CGADD) + _state.CgramAddress = value; + _state.CgramAddressLatch = false; + break; - case 0x2120: - //M7Y - Mode 7 Center Y - _state.Mode7.CenterY = ((value << 8) | _state.Mode7.ValueLatch); - _state.Mode7.ValueLatch = value; - break; + case 0x2122: + //CGRAM Data write (CGDATA) + if (_state.CgramAddressLatch) + { + //MSB ignores the 7th bit (colors are 15-bit only) + _console->ProcessPpuWrite(_state.CgramAddress >> 1, _state.CgramWriteBuffer, SnesMemoryType::CGRam); + _console->ProcessPpuWrite((_state.CgramAddress >> 1) + 1, value & 0x7F, SnesMemoryType::CGRam); - case 0x2121: - //CGRAM Address(CGADD) - _state.CgramAddress = value; - _state.CgramAddressLatch = false; - break; + _cgram[_state.CgramAddress] = _state.CgramWriteBuffer | ((value & 0x7F) << 8); + _state.CgramAddress++; + } + else + { + _state.CgramWriteBuffer = value; + } + _state.CgramAddressLatch = !_state.CgramAddressLatch; + break; - case 0x2122: - //CGRAM Data write (CGDATA) - if(_state.CgramAddressLatch) { - //MSB ignores the 7th bit (colors are 15-bit only) - _console->ProcessPpuWrite(_state.CgramAddress >> 1, _state.CgramWriteBuffer, SnesMemoryType::CGRam); - _console->ProcessPpuWrite((_state.CgramAddress >> 1) + 1, value & 0x7F, SnesMemoryType::CGRam); + case 0x2123: + //W12SEL - Window Mask Settings for BG1 and BG2 + ProcessWindowMaskSettings(value, 0); + break; - _cgram[_state.CgramAddress] = _state.CgramWriteBuffer | ((value & 0x7F) << 8); - _state.CgramAddress++; - } else { - _state.CgramWriteBuffer = value; - } - _state.CgramAddressLatch = !_state.CgramAddressLatch; - break; + case 0x2124: + //W34SEL - Window Mask Settings for BG3 and BG4 + ProcessWindowMaskSettings(value, 2); + break; - case 0x2123: - //W12SEL - Window Mask Settings for BG1 and BG2 - ProcessWindowMaskSettings(value, 0); - break; + case 0x2125: + //WOBJSEL - Window Mask Settings for OBJ and Color Window + ProcessWindowMaskSettings(value, 4); + break; - case 0x2124: - //W34SEL - Window Mask Settings for BG3 and BG4 - ProcessWindowMaskSettings(value, 2); - break; + case 0x2126: + //WH0 - Window 1 Left Position + _state.Window[0].Left = value; + break; - case 0x2125: - //WOBJSEL - Window Mask Settings for OBJ and Color Window - ProcessWindowMaskSettings(value, 4); - break; + case 0x2127: + //WH1 - Window 1 Right Position + _state.Window[0].Right = value; + break; - case 0x2126: - //WH0 - Window 1 Left Position - _state.Window[0].Left = value; - break; - - case 0x2127: - //WH1 - Window 1 Right Position - _state.Window[0].Right = value; - break; + case 0x2128: + //WH2 - Window 2 Left Position + _state.Window[1].Left = value; + break; - case 0x2128: - //WH2 - Window 2 Left Position - _state.Window[1].Left = value; - break; + case 0x2129: + //WH3 - Window 2 Right Position + _state.Window[1].Right = value; + break; - case 0x2129: - //WH3 - Window 2 Right Position - _state.Window[1].Right = value; - break; + case 0x212A: + //WBGLOG - Window mask logic for BG + _state.MaskLogic[0] = (WindowMaskLogic)(value & 0x03); + _state.MaskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03); + _state.MaskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03); + _state.MaskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03); + break; - case 0x212A: - //WBGLOG - Window mask logic for BG - _state.MaskLogic[0] = (WindowMaskLogic)(value & 0x03); - _state.MaskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03); - _state.MaskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03); - _state.MaskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03); - break; + case 0x212B: + //WOBJLOG - Window mask logic for OBJs and Color Window + _state.MaskLogic[4] = (WindowMaskLogic)((value >> 0) & 0x03); + _state.MaskLogic[5] = (WindowMaskLogic)((value >> 2) & 0x03); + break; - case 0x212B: - //WOBJLOG - Window mask logic for OBJs and Color Window - _state.MaskLogic[4] = (WindowMaskLogic)((value >> 0) & 0x03); - _state.MaskLogic[5] = (WindowMaskLogic)((value >> 2) & 0x03); - break; + case 0x212C: + //TM - Main Screen Designation + _state.MainScreenLayers = value & 0x1F; + break; - case 0x212C: - //TM - Main Screen Designation - _state.MainScreenLayers = value & 0x1F; - break; + case 0x212D: + //TS - Subscreen Designation + _state.SubScreenLayers = value & 0x1F; + break; - case 0x212D: - //TS - Subscreen Designation - _state.SubScreenLayers = value & 0x1F; - break; + case 0x212E: + //TMW - Window Mask Designation for the Main Screen + for (int i = 0; i < 5; i++) + { + _state.WindowMaskMain[i] = ((value >> i) & 0x01) != 0; + } + break; - case 0x212E: - //TMW - Window Mask Designation for the Main Screen - for(int i = 0; i < 5; i++) { - _state.WindowMaskMain[i] = ((value >> i) & 0x01) != 0; - } - break; + case 0x212F: + //TSW - Window Mask Designation for the Subscreen + for (int i = 0; i < 5; i++) + { + _state.WindowMaskSub[i] = ((value >> i) & 0x01) != 0; + } + break; - case 0x212F: - //TSW - Window Mask Designation for the Subscreen - for(int i = 0; i < 5; i++) { - _state.WindowMaskSub[i] = ((value >> i) & 0x01) != 0; - } - break; - - case 0x2130: - //CGWSEL - Color Addition Select - _state.ColorMathClipMode = (ColorWindowMode)((value >> 6) & 0x03); - _state.ColorMathPreventMode = (ColorWindowMode)((value >> 4) & 0x03); - _state.ColorMathAddSubscreen = (value & 0x02) != 0; - _state.DirectColorMode = (value & 0x01) != 0; - break; + case 0x2130: + //CGWSEL - Color Addition Select + _state.ColorMathClipMode = (ColorWindowMode)((value >> 6) & 0x03); + _state.ColorMathPreventMode = (ColorWindowMode)((value >> 4) & 0x03); + _state.ColorMathAddSubscreen = (value & 0x02) != 0; + _state.DirectColorMode = (value & 0x01) != 0; + break; - case 0x2131: - //CGADSUB - Color math designation - _state.ColorMathEnabled = value & 0x3F; - _state.ColorMathSubstractMode = (value & 0x80) != 0; - _state.ColorMathHalveResult = (value & 0x40) != 0; - break; + case 0x2131: + //CGADSUB - Color math designation + _state.ColorMathEnabled = value & 0x3F; + _state.ColorMathSubstractMode = (value & 0x80) != 0; + _state.ColorMathHalveResult = (value & 0x40) != 0; + break; - case 0x2132: - //COLDATA - Fixed Color Data - if(value & 0x80) { //B - _state.FixedColor = (_state.FixedColor & ~0x7C00) | ((value & 0x1F) << 10); - } - if(value & 0x40) { //G - _state.FixedColor = (_state.FixedColor & ~0x3E0) | ((value & 0x1F) << 5); - } - if(value & 0x20) { //R - _state.FixedColor = (_state.FixedColor & ~0x1F) | (value & 0x1F); - } - break; + case 0x2132: + //COLDATA - Fixed Color Data + if (value & 0x80) + { + //B + _state.FixedColor = (_state.FixedColor & ~0x7C00) | ((value & 0x1F) << 10); + } + if (value & 0x40) + { + //G + _state.FixedColor = (_state.FixedColor & ~0x3E0) | ((value & 0x1F) << 5); + } + if (value & 0x20) + { + //R + _state.FixedColor = (_state.FixedColor & ~0x1F) | (value & 0x1F); + } + break; - case 0x2133: { + case 0x2133: + { //SETINI - Screen Mode/Video Select //_externalSync = (value & 0x80) != 0; //NOT USED _state.ExtBgEnabled = (value & 0x40) != 0; @@ -2092,9 +2529,11 @@ void Ppu::Write(uint32_t addr, uint8_t value) _state.ObjInterlace = (value & 0x02) != 0; bool interlace = (value & 0x01) != 0; - if(_state.ScreenInterlace != interlace) { + if (_state.ScreenInterlace != interlace) + { _state.ScreenInterlace = interlace; - if(_scanline >= _vblankStartScanline && interlace) { + if (_scanline >= _vblankStartScanline && interlace) + { //Clear buffer when turning on interlace mode during vblank memset(GetPreviousScreenBuffer(), 0, 512 * 478 * sizeof(uint16_t)); } @@ -2103,45 +2542,64 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - default: - LogDebug("[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); - break; + default: + LogDebug( + "[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); + break; } } -void Ppu::Serialize(Serializer &s) +void Ppu::Serialize(Serializer& s) { uint16_t unused_oamRenderAddress = 0; s.Stream( _state.ForcedVblank, _state.ScreenBrightness, _scanline, _frameCount, _drawStartX, _drawEndX, _state.BgMode, - _state.Mode1Bg3Priority, _state.MainScreenLayers, _state.SubScreenLayers, _state.VramAddress, _state.VramIncrementValue, _state.VramAddressRemapping, - _state.VramAddrIncrementOnSecondReg, _state.VramReadBuffer, _state.Ppu1OpenBus, _state.Ppu2OpenBus, _state.CgramAddress, _state.MosaicSize, _state.MosaicEnabled, - _mosaicScanlineCounter, _state.OamMode, _state.OamBaseAddress, _state.OamAddressOffset, _state.OamRamAddress, _state.EnableOamPriority, - _internalOamAddress, _oamWriteBuffer, _timeOver, _rangeOver, _state.HiResMode, _state.ScreenInterlace, _state.ObjInterlace, - _state.OverscanMode, _state.DirectColorMode, _state.ColorMathClipMode, _state.ColorMathPreventMode, _state.ColorMathAddSubscreen, _state.ColorMathEnabled, - _state.ColorMathSubstractMode, _state.ColorMathHalveResult, _state.FixedColor, _hvScrollLatchValue, _hScrollLatchValue, + _state.Mode1Bg3Priority, _state.MainScreenLayers, _state.SubScreenLayers, _state.VramAddress, + _state.VramIncrementValue, _state.VramAddressRemapping, + _state.VramAddrIncrementOnSecondReg, _state.VramReadBuffer, _state.Ppu1OpenBus, _state.Ppu2OpenBus, + _state.CgramAddress, _state.MosaicSize, _state.MosaicEnabled, + _mosaicScanlineCounter, _state.OamMode, _state.OamBaseAddress, _state.OamAddressOffset, _state.OamRamAddress, + _state.EnableOamPriority, + _internalOamAddress, _oamWriteBuffer, _timeOver, _rangeOver, _state.HiResMode, _state.ScreenInterlace, + _state.ObjInterlace, + _state.OverscanMode, _state.DirectColorMode, _state.ColorMathClipMode, _state.ColorMathPreventMode, + _state.ColorMathAddSubscreen, _state.ColorMathEnabled, + _state.ColorMathSubstractMode, _state.ColorMathHalveResult, _state.FixedColor, _hvScrollLatchValue, + _hScrollLatchValue, _horizontalLocation, _horizontalLocToggle, _verticalLocation, _verticalLocationToggle, _locationLatched, - _state.MaskLogic[0], _state.MaskLogic[1], _state.MaskLogic[2], _state.MaskLogic[3], _state.MaskLogic[4], _state.MaskLogic[5], - _state.WindowMaskMain[0], _state.WindowMaskMain[1], _state.WindowMaskMain[2], _state.WindowMaskMain[3], _state.WindowMaskMain[4], - _state.WindowMaskSub[0], _state.WindowMaskSub[1], _state.WindowMaskSub[2], _state.WindowMaskSub[3], _state.WindowMaskSub[4], - _state.Mode7.CenterX, _state.Mode7.CenterY, _state.ExtBgEnabled, _state.Mode7.FillWithTile0, _state.Mode7.HorizontalMirroring, - _state.Mode7.HScroll, _state.Mode7.LargeMap, _state.Mode7.Matrix[0], _state.Mode7.Matrix[1], _state.Mode7.Matrix[2], _state.Mode7.Matrix[3], - _state.Mode7.ValueLatch, _state.Mode7.VerticalMirroring, _state.Mode7.VScroll, unused_oamRenderAddress, _oddFrame, _vblankStartScanline, - _state.CgramAddressLatch, _state.CgramWriteBuffer, _nmiScanline, _vblankEndScanline, _adjustedVblankEndScanline, _baseVblankEndScanline, + _state.MaskLogic[0], _state.MaskLogic[1], _state.MaskLogic[2], _state.MaskLogic[3], _state.MaskLogic[4], + _state.MaskLogic[5], + _state.WindowMaskMain[0], _state.WindowMaskMain[1], _state.WindowMaskMain[2], _state.WindowMaskMain[3], + _state.WindowMaskMain[4], + _state.WindowMaskSub[0], _state.WindowMaskSub[1], _state.WindowMaskSub[2], _state.WindowMaskSub[3], + _state.WindowMaskSub[4], + _state.Mode7.CenterX, _state.Mode7.CenterY, _state.ExtBgEnabled, _state.Mode7.FillWithTile0, + _state.Mode7.HorizontalMirroring, + _state.Mode7.HScroll, _state.Mode7.LargeMap, _state.Mode7.Matrix[0], _state.Mode7.Matrix[1], + _state.Mode7.Matrix[2], _state.Mode7.Matrix[3], + _state.Mode7.ValueLatch, _state.Mode7.VerticalMirroring, _state.Mode7.VScroll, unused_oamRenderAddress, _oddFrame, + _vblankStartScanline, + _state.CgramAddressLatch, _state.CgramWriteBuffer, _nmiScanline, _vblankEndScanline, _adjustedVblankEndScanline, + _baseVblankEndScanline, _overclockEnabled ); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { s.Stream( - _state.Layers[i].ChrAddress, _state.Layers[i].DoubleHeight, _state.Layers[i].DoubleWidth, _state.Layers[i].HScroll, + _state.Layers[i].ChrAddress, _state.Layers[i].DoubleHeight, _state.Layers[i].DoubleWidth, + _state.Layers[i].HScroll, _state.Layers[i].LargeTiles, _state.Layers[i].TilemapAddress, _state.Layers[i].VScroll ); } - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { s.Stream( - _state.Window[i].ActiveLayers[0], _state.Window[i].ActiveLayers[1], _state.Window[i].ActiveLayers[2], _state.Window[i].ActiveLayers[3], _state.Window[i].ActiveLayers[4], _state.Window[i].ActiveLayers[5], - _state.Window[i].InvertedLayers[0], _state.Window[i].InvertedLayers[1], _state.Window[i].InvertedLayers[2], _state.Window[i].InvertedLayers[3], _state.Window[i].InvertedLayers[4], _state.Window[i].InvertedLayers[5], + _state.Window[i].ActiveLayers[0], _state.Window[i].ActiveLayers[1], _state.Window[i].ActiveLayers[2], + _state.Window[i].ActiveLayers[3], _state.Window[i].ActiveLayers[4], _state.Window[i].ActiveLayers[5], + _state.Window[i].InvertedLayers[0], _state.Window[i].InvertedLayers[1], _state.Window[i].InvertedLayers[2], + _state.Window[i].InvertedLayers[3], _state.Window[i].InvertedLayers[4], _state.Window[i].InvertedLayers[5], _state.Window[i].Left, _state.Window[i].Right ); } @@ -2149,11 +2607,14 @@ void Ppu::Serialize(Serializer &s) s.StreamArray(_vram, Ppu::VideoRamSize >> 1); s.StreamArray(_oamRam, Ppu::SpriteRamSize); s.StreamArray(_cgram, Ppu::CgRamSize >> 1); - - for(int i = 0; i < 4; i++) { - for(int j = 0; j < 33; j++) { + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 33; j++) + { s.Stream( - _layerData[i].Tiles[j].ChrData[0], _layerData[i].Tiles[j].ChrData[1], _layerData[i].Tiles[j].ChrData[2], _layerData[i].Tiles[j].ChrData[3], + _layerData[i].Tiles[j].ChrData[0], _layerData[i].Tiles[j].ChrData[1], _layerData[i].Tiles[j].ChrData[2], + _layerData[i].Tiles[j].ChrData[3], _layerData[i].Tiles[j].TilemapData, _layerData[i].Tiles[j].VScroll ); } @@ -2185,7 +2646,8 @@ void Ppu::RandomizeState() _state.MainScreenLayers = _settings->GetRandomValue(0x1F); _state.SubScreenLayers = _settings->GetRandomValue(0x1F); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _state.Layers[i].TilemapAddress = _settings->GetRandomValue(0x1F) << 10; _state.Layers[i].ChrAddress = _settings->GetRandomValue(0x07) << 12; _state.Layers[i].HScroll = _settings->GetRandomValue(0x1FFF); @@ -2195,29 +2657,38 @@ void Ppu::RandomizeState() _state.Layers[i].LargeTiles = _settings->GetRandomBool(); } - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { _state.Window[i].Left = _settings->GetRandomValue(0xFF); _state.Window[i].Right = _settings->GetRandomValue(0xFF); - for(int j = 0; j < 6; j++) { + for (int j = 0; j < 6; j++) + { _state.Window[i].ActiveLayers[j] = _settings->GetRandomBool(); _state.Window[i].InvertedLayers[j] = _settings->GetRandomBool(); } } - for(int i = 0; i < 6; i++) { + for (int i = 0; i < 6; i++) + { _state.MaskLogic[i] = (WindowMaskLogic)_settings->GetRandomValue(3); } - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { _state.WindowMaskMain[i] = _settings->GetRandomBool(); _state.WindowMaskSub[i] = _settings->GetRandomBool(); } _state.VramAddress = _settings->GetRandomValue(0x7FFF); - switch(_settings->GetRandomValue(0x03)) { - case 0: _state.VramIncrementValue = 1; break; - case 1: _state.VramIncrementValue = 32; break; - case 2: case 3: _state.VramIncrementValue = 128; break; + switch (_settings->GetRandomValue(0x03)) + { + case 0: _state.VramIncrementValue = 1; + break; + case 1: _state.VramIncrementValue = 32; + break; + case 2: + case 3: _state.VramIncrementValue = 128; + break; } _state.VramAddressRemapping = _settings->GetRandomValue(0x03); @@ -2257,64 +2728,84 @@ void Ppu::RandomizeState() } /* Everything below this point is used to select the proper arguments for templates */ -template +template void Ppu::RenderTilemap() { - if(_state.DirectColorMode) { + if (_state.DirectColorMode) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemap() { - bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0 && (_state.MosaicSize > 1 || _state.BgMode == 5 || _state.BgMode == 6); + bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0 && (_state.MosaicSize > 1 || _state.BgMode == 5 + || _state.BgMode == 6); - if(applyMosaic) { + if (applyMosaic) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemap() { - if(!IsRenderRequired(layerIndex)) { + if (!IsRenderRequired(layerIndex)) + { return; } - if(_state.BgMode == 5 || _state.BgMode == 6) { + if (_state.BgMode == 5 || _state.BgMode == 6) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemapMode7() { - if(!IsRenderRequired(layerIndex)) { + if (!IsRenderRequired(layerIndex)) + { return; } bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0; - if(applyMosaic) { + if (applyMosaic) + { RenderTilemapMode7(); - } else { + } + else + { RenderTilemapMode7(); } } -template +template void Ppu::RenderTilemapMode7() { - if(_state.DirectColorMode) { + if (_state.DirectColorMode) + { RenderTilemapMode7(); - } else { + } + else + { RenderTilemapMode7(); } -} \ No newline at end of file +} diff --git a/Core/Ppu.h b/Core/Ppu.h index eb2d446..5f410dc 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -64,13 +64,13 @@ private: uint16_t _drawStartX = 0; uint16_t _drawEndX = 0; - - uint16_t *_vram = nullptr; + + uint16_t* _vram = nullptr; uint16_t _cgram[Ppu::CgRamSize >> 1] = {}; uint8_t _oamRam[Ppu::SpriteRamSize] = {}; - uint16_t *_outputBuffers[2] = {}; - uint16_t *_currentBuffer = nullptr; + uint16_t* _outputBuffers[2] = {}; + uint16_t* _currentBuffer = nullptr; bool _useHighResOutput = false; bool _interlacedFrame = false; bool _overscanFrame = false; @@ -84,7 +84,7 @@ private: uint32_t _mosaicColor[4] = {}; uint32_t _mosaicPriority[4] = {}; uint16_t _mosaicScanlineCounter = 0; - + uint16_t _internalOamAddress = 0; uint8_t _oamWriteBuffer = 0; @@ -116,10 +116,10 @@ private: void RenderSprites(const uint8_t priorities[4]); - template + template void GetTilemapData(uint8_t layerIndex, uint8_t columnIndex); - template + template void GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane); void GetHorizontalOffsetByte(uint8_t columnIndex); @@ -137,48 +137,52 @@ private: void RenderBgColor(); - template - __forceinline void RenderTilemap(); - - template + template __forceinline void RenderTilemap(); - template + template __forceinline void RenderTilemap(); - template + template + __forceinline void RenderTilemap(); + + template void RenderTilemap(); - template + template __forceinline uint16_t GetRgbColor(uint8_t paletteIndex, uint8_t colorIndex); __forceinline bool IsRenderRequired(uint8_t layerIndex); - template + template __forceinline uint8_t GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift); - template + template __forceinline void RenderTilemapMode7(); - template + template __forceinline void RenderTilemapMode7(); - template + template void RenderTilemapMode7(); __forceinline void DrawMainPixel(uint8_t x, uint16_t color, uint8_t flags); __forceinline void DrawSubPixel(uint8_t x, uint16_t color, uint8_t priority); void ApplyColorMath(); - void ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool isInsideWindow); - - template + void ApplyColorMathToPixel(uint16_t& pixelA, uint16_t pixelB, int x, bool isInsideWindow); + + template void ApplyBrightness(); void ConvertToHiRes(); void ApplyHiResMode(); - template + template bool ProcessMaskWindow(uint8_t activeWindowCount, int x); void ProcessWindowMaskSettings(uint8_t value, uint8_t offset); @@ -199,7 +203,7 @@ private: void UpdateOamAddress(); uint16_t GetOamAddress(); - + void RandomizeState(); public: @@ -220,7 +224,7 @@ public: uint16_t GetVblankStart(); PpuState GetState(); - void GetState(PpuState &state, bool returnPartialState); + void GetState(PpuState& state, bool returnPartialState); bool ProcessEndOfScanline(uint16_t hClock); void UpdateSpcState(); @@ -237,9 +241,9 @@ public: void SetLocationLatchRequest(uint16_t x, uint16_t y); void ProcessLocationLatchRequest(); void LatchLocationValues(); - + uint8_t Read(uint16_t addr); void Write(uint32_t addr, uint8_t value); - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/PpuTools.cpp b/Core/PpuTools.cpp index ec20c0c..93a746d 100644 --- a/Core/PpuTools.cpp +++ b/Core/PpuTools.cpp @@ -9,24 +9,30 @@ #include "DefaultVideoFilter.h" #include "GbTypes.h" -PpuTools::PpuTools(Console *console, Ppu *ppu) +PpuTools::PpuTools(Console* console, Ppu* ppu) { _console = console; _ppu = ppu; } -uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift) +uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, + const uint32_t pixelStart, const uint8_t shift) { uint8_t color; - if(bpp == 2) { + if (bpp == 2) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); - } else if(bpp == 4) { + } + else if (bpp == 4) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); color |= (((ram[(pixelStart + 16) & ramMask] >> shift) & 0x01) << 2); color |= (((ram[(pixelStart + 17) & ramMask] >> shift) & 0x01) << 3); - } else if(bpp == 8) { + } + else if (bpp == 8) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); color |= (((ram[(pixelStart + 16) & ramMask] >> shift) & 0x01) << 2); @@ -35,7 +41,9 @@ uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, color |= (((ram[(pixelStart + 33) & ramMask] >> shift) & 0x01) << 5); color |= (((ram[(pixelStart + 48) & ramMask] >> shift) & 0x01) << 6); color |= (((ram[(pixelStart + 49) & ramMask] >> shift) & 0x01) << 7); - } else { + } + else + { throw std::runtime_error("unsupported bpp"); } return color; @@ -51,23 +59,28 @@ void PpuTools::BlendColors(uint8_t output[4], uint8_t input[4]) output[3] = 0xFF; } -uint32_t PpuTools::GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, uint16_t basePaletteOffset) +uint32_t PpuTools::GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, + bool directColorMode, uint16_t basePaletteOffset) { uint16_t paletteColor; - if(bpp == 8 && directColorMode) { + if (bpp == 8 && directColorMode) + { paletteColor = ( ((((colorIndex & 0x07) << 1) | (palette & 0x01)) << 1) | (((colorIndex & 0x38) | ((palette & 0x02) << 1)) << 4) | (((colorIndex & 0xC0) | ((palette & 0x04) << 3)) << 7) ); - } else { + } + else + { uint16_t paletteRamOffset = basePaletteOffset + (palette * (1 << bpp) + colorIndex) * 2; paletteColor = cgram[paletteRamOffset] | (cgram[paletteRamOffset + 1] << 8); } return DefaultVideoFilter::ToArgb(paletteColor); } -void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint8_t *cgram, uint32_t *outBuffer) +void PpuTools::GetTileView(GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint8_t* cgram, + uint32_t* outBuffer) { constexpr uint32_t inputSize = 0x40000; constexpr uint32_t outputSize = 0x400000; @@ -77,77 +90,115 @@ void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t uint8_t bpp; bool directColor = false; - switch(options.Format) { - case TileFormat::Bpp2: bpp = 2; break; - case TileFormat::Bpp4: bpp = 4; break; - case TileFormat::DirectColor: directColor = true; bpp = 8; break; - case TileFormat::Mode7: bpp = 16; break; - case TileFormat::Mode7DirectColor: directColor = true; bpp = 16; break; - default: bpp = 8; break; + switch (options.Format) + { + case TileFormat::Bpp2: bpp = 2; + break; + case TileFormat::Bpp4: bpp = 4; + break; + case TileFormat::DirectColor: directColor = true; + bpp = 8; + break; + case TileFormat::Mode7: bpp = 16; + break; + case TileFormat::Mode7DirectColor: directColor = true; + bpp = 16; + break; + default: bpp = 8; + break; } int bytesPerTile = 64 * bpp / 8; int tileCount = options.PageSize / bytesPerTile; uint32_t bgColor = 0; - switch(options.Background) { - case TileBackground::Default: bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); break; - case TileBackground::PaletteColor: bgColor = DefaultVideoFilter::ToArgb(0); break; - case TileBackground::Black: bgColor = DefaultVideoFilter::ToArgb(0); break; - case TileBackground::White: bgColor = DefaultVideoFilter::ToArgb(0x7FFF); break; - case TileBackground::Magenta: bgColor = DefaultVideoFilter::ToArgb(0x7C1F); break; + switch (options.Background) + { + case TileBackground::Default: bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); + break; + case TileBackground::PaletteColor: bgColor = DefaultVideoFilter::ToArgb(0); + break; + case TileBackground::Black: bgColor = DefaultVideoFilter::ToArgb(0); + break; + case TileBackground::White: bgColor = DefaultVideoFilter::ToArgb(0x7FFF); + break; + case TileBackground::Magenta: bgColor = DefaultVideoFilter::ToArgb(0x7C1F); + break; } - for(uint32_t i = 0; i < outputSize / sizeof(uint32_t); i++) { + for (uint32_t i = 0; i < outputSize / sizeof(uint32_t); i++) + { outBuffer[i] = bgColor; } int rowCount = (int)std::ceil((double)tileCount / options.Width); - for(int row = 0; row < rowCount; row++) { + for (int row = 0; row < rowCount; row++) + { uint32_t baseOffset = row * bytesPerTile * options.Width; - for(int column = 0; column < options.Width; column++) { + for (int column = 0; column < options.Width; column++) + { uint32_t addr = baseOffset + bytesPerTile * column; - int baseOutputOffset; - if(options.Layout == TileLayout::SingleLine8x16) { - int displayColumn = column / 2 + ((row & 0x01) ? options.Width/2 : 0); + int baseOutputOffset; + if (options.Layout == TileLayout::SingleLine8x16) + { + int displayColumn = column / 2 + ((row & 0x01) ? options.Width / 2 : 0); int displayRow = (row & ~0x01) + ((column & 0x01) ? 1 : 0); baseOutputOffset = displayRow * options.Width * 64 + displayColumn * 8; - } else if(options.Layout == TileLayout::SingleLine16x16) { - int displayColumn = (column / 2) + (column & 0x01) + ((row & 0x01) ? options.Width/2 : 0) + ((column & 0x02) ? -1 : 0); + } + else if (options.Layout == TileLayout::SingleLine16x16) + { + int displayColumn = (column / 2) + (column & 0x01) + ((row & 0x01) ? options.Width / 2 : 0) + ( + (column & 0x02) ? -1 : 0); int displayRow = (row & ~0x01) + ((column & 0x02) ? 1 : 0); baseOutputOffset = displayRow * options.Width * 64 + displayColumn * 8; - } else { + } + else + { baseOutputOffset = row * options.Width * 64 + column * 8; } - if(options.Format == TileFormat::Mode7 || options.Format == TileFormat::Mode7DirectColor) { - for(int y = 0; y < 8; y++) { + if (options.Format == TileFormat::Mode7 || options.Format == TileFormat::Mode7DirectColor) + { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = addr + y * 16; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = ram[(pixelStart + x * 2 + 1) & ramMask]; - if(color != 0 || options.Background == TileBackground::PaletteColor) { + if (color != 0 || options.Background == TileBackground::PaletteColor) + { uint32_t rgbColor; - if(directColor) { - rgbColor = DefaultVideoFilter::ToArgb(((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); - } else { + if (directColor) + { + rgbColor = DefaultVideoFilter::ToArgb( + ((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); + } + else + { rgbColor = GetRgbPixelColor(cgram, color, 0, 8, false, 0); } - outBuffer[baseOutputOffset + (y*options.Width*8) + x] = rgbColor; + outBuffer[baseOutputOffset + (y * options.Width * 8) + x] = rgbColor; } } } - } else { - for(int y = 0; y < 8; y++) { + } + else + { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = addr + y * 2; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = GetTilePixelColor(ram, ramMask, bpp, pixelStart, 7 - x); - if(color != 0 || options.Background == TileBackground::PaletteColor) { - outBuffer[baseOutputOffset + (y*options.Width*8) + x] = GetRgbPixelColor(cgram, color, options.Palette, bpp, directColor, 0); + if (color != 0 || options.Background == TileBackground::PaletteColor) + { + outBuffer[baseOutputOffset + (y * options.Width * 8) + x] = GetRgbPixelColor( + cgram, color, options.Palette, bpp, directColor, 0); } } } @@ -159,46 +210,58 @@ void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t* outBuffer) { static constexpr uint8_t layerBpp[8][4] = { - { 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 } + {2, 2, 2, 2}, {4, 4, 2, 0}, {4, 4, 0, 0}, {8, 4, 0, 0}, {8, 2, 0, 0}, {4, 2, 0, 0}, {4, 0, 0, 0}, {8, 0, 0, 0} }; bool directColor = state.DirectColorMode && (state.BgMode == 3 || state.BgMode == 4 || state.BgMode == 7); uint16_t basePaletteOffset = 0; - if(state.BgMode == 0) { + if (state.BgMode == 0) + { basePaletteOffset = options.Layer * 64; } LayerConfig layer = state.Layers[options.Layer]; uint32_t bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); - std::fill(outBuffer, outBuffer + 1024*1024, bgColor); + std::fill(outBuffer, outBuffer + 1024 * 1024, bgColor); uint8_t bpp = layerBpp[state.BgMode][options.Layer]; - if(bpp == 0) { + if (bpp == 0) + { return; } bool largeTileWidth = layer.LargeTiles || state.BgMode == 5 || state.BgMode == 6; bool largeTileHeight = layer.LargeTiles; - if(state.BgMode == 7) { - for(int row = 0; row < 128; row++) { - for(int column = 0; column < 128; column++) { + if (state.BgMode == 7) + { + for (int row = 0; row < 128; row++) + { + for (int column = 0; column < 128; column++) + { uint32_t tileIndex = vram[row * 256 + column * 2]; uint32_t tileAddr = tileIndex * 128; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = tileAddr + y * 16; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = vram[pixelStart + x * 2 + 1]; - if(color != 0) { + if (color != 0) + { uint32_t rgbColor; - if(directColor) { - rgbColor = DefaultVideoFilter::ToArgb(((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); - } else { + if (directColor) + { + rgbColor = DefaultVideoFilter::ToArgb( + ((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); + } + else + { rgbColor = GetRgbPixelColor(cgram, color, 0, 8, false, 0); } outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = rgbColor; @@ -207,24 +270,30 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr } } } - } else { + } + else + { int tileHeight = largeTileHeight ? 16 : 8; int tileWidth = largeTileWidth ? 16 : 8; - for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) { + for (int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) + { uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; uint16_t baseOffset = layer.TilemapAddress + addrVerticalScrollingOffset + ((row & 0x1F) << 5); - for(int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) { + for (int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) + { uint16_t addr = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1; bool vMirror = (vram[addr + 1] & 0x80) != 0; bool hMirror = (vram[addr + 1] & 0x40) != 0; uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr]; - for(int y = 0; y < tileHeight; y++) { + for (int y = 0; y < tileHeight; y++) + { uint8_t yOffset = vMirror ? (7 - (y & 0x07)) : (y & 0x07); - for(int x = 0; x < tileWidth; x++) { + for (int x = 0; x < tileWidth; x++) + { uint16_t tileOffset = ( (largeTileHeight ? ((y & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + (largeTileWidth ? ((x & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) @@ -235,9 +304,11 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, bpp, pixelStart, shift); - if(color != 0) { + if (color != 0) + { uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07; - outBuffer[((row * tileHeight) + y) * 1024 + column * tileWidth + x] = GetRgbPixelColor(cgram, color, palette, bpp, directColor, basePaletteOffset); + outBuffer[((row * tileHeight) + y) * 1024 + column * tileWidth + x] = GetRgbPixelColor( + cgram, color, palette, bpp, directColor, basePaletteOffset); } } } @@ -247,17 +318,18 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr } static constexpr uint8_t _oamSizes[8][2][2] = { - { { 1, 1 }, { 2, 2 } }, //8x8 + 16x16 - { { 1, 1 }, { 4, 4 } }, //8x8 + 32x32 - { { 1, 1 }, { 8, 8 } }, //8x8 + 64x64 - { { 2, 2 }, { 4, 4 } }, //16x16 + 32x32 - { { 2, 2 }, { 8, 8 } }, //16x16 + 64x64 - { { 4, 4 }, { 8, 8 } }, //32x32 + 64x64 - { { 2, 4 }, { 4, 8 } }, //16x32 + 32x64 - { { 2, 4 }, { 4, 4 } } //16x32 + 32x32 + {{1, 1}, {2, 2}}, //8x8 + 16x16 + {{1, 1}, {4, 4}}, //8x8 + 32x32 + {{1, 1}, {8, 8}}, //8x8 + 64x64 + {{2, 2}, {4, 4}}, //16x16 + 32x32 + {{2, 2}, {8, 8}}, //16x16 + 64x64 + {{4, 4}, {8, 8}}, //32x32 + 64x64 + {{2, 4}, {4, 8}}, //16x32 + 32x64 + {{2, 4}, {4, 4}} //16x32 + 32x32 }; -void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t *vram, uint8_t *oamRam, uint8_t *cgram, uint32_t *outBuffer) +void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, + uint8_t* cgram, uint32_t* outBuffer) { //TODO //uint16_t baseAddr = state.EnableOamPriority ? (_internalOamAddress & 0x1FC) : 0; @@ -268,8 +340,10 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, std::fill(outBuffer, outBuffer + 256 * lastScanline, 0xFF888888); std::fill(outBuffer + 256 * lastScanline, outBuffer + 256 * 240, 0xFF000000); - for(int screenY = 0; screenY < lastScanline; screenY++) { - for(int i = 508; i >= 0; i -= 4) { + for (int screenY = 0; screenY < lastScanline; screenY++) + { + for (int i = 508; i >= 0; i -= 4) + { uint16_t addr = (baseAddr + i) & 0x1FF; uint8_t y = oamRam[addr + 1]; @@ -279,10 +353,11 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t largeSprite = (highTableValue & 0x02) >> 1; uint8_t height = _oamSizes[state.OamMode][largeSprite][1] << 3; - uint8_t endY = (y + (state.ObjInterlace ? (height >> 1): height)) & 0xFF; + uint8_t endY = (y + (state.ObjInterlace ? (height >> 1) : height)) & 0xFF; bool visible = (screenY >= y && screenY < endY) || (endY < y && screenY < endY); - if(!visible) { + if (!visible) + { //Not visible on this scanline continue; } @@ -291,7 +366,8 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint16_t sign = (highTableValue & 0x01) << 8; int16_t x = (int16_t)((sign | oamRam[addr]) << 7) >> 7; - if(x != -256 && (x + width <= 0 || x > 255)) { + if (x != -256 && (x + width <= 0 || x > 255)) + { //Sprite is not visible (and must be ignored for time/range flag calculations) //Sprites at X=-256 are always used when considering Time/Range flag calculations, but not actually drawn. continue; @@ -306,49 +382,62 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, //uint8_t priority = (flags >> 4) & 0x03; bool horizontalMirror = (flags & 0x40) != 0; bool verticalMirror = (flags & 0x80) != 0; - + uint8_t yOffset; int rowOffset; int yGap = (screenY - y); - if(state.ObjInterlace) { + if (state.ObjInterlace) + { yGap <<= 1; yGap |= (state.FrameCount & 0x01); } - if(verticalMirror) { + if (verticalMirror) + { yOffset = (height - 1 - yGap) & 0x07; rowOffset = (height - 1 - yGap) >> 3; - } else { + } + else + { yOffset = yGap & 0x07; rowOffset = yGap >> 3; } uint8_t row = (tileRow + rowOffset) & 0x0F; - for(int j = std::max(x, 0); j < x + width && j < 256; j++) { + for (int j = std::max(x, 0); j < x + width && j < 256; j++) + { uint32_t outOffset = screenY * 256 + j; - if(filled[outOffset]) { + if (filled[outOffset]) + { continue; } uint8_t xOffset; int columnOffset; - if(horizontalMirror) { + if (horizontalMirror) + { xOffset = (width - (j - x) - 1) & 0x07; columnOffset = (width - (j - x) - 1) >> 3; - } else { + } + else + { xOffset = (j - x) & 0x07; columnOffset = (j - x) >> 3; } uint8_t column = (tileColumn + columnOffset) & 0x0F; uint8_t tileIndex = (row << 4) | column; - uint16_t tileStart = ((state.OamBaseAddress + (tileIndex << 4) + (useSecondTable ? state.OamAddressOffset : 0)) & 0x7FFF) << 1; + uint16_t tileStart = ((state.OamBaseAddress + (tileIndex << 4) + (useSecondTable + ? state.OamAddressOffset + : 0)) & 0x7FFF) << 1; uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, 4, tileStart + yOffset * 2, 7 - xOffset); - if(color != 0) { - if(options.SelectedSprite == i / 4) { + if (color != 0) + { + if (options.SelectedSprite == i / 4) + { filled[outOffset] = true; } outBuffer[outOffset] = GetRgbPixelColor(cgram, color, palette, 4, false, 256); @@ -380,14 +469,16 @@ void PpuTools::GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offs uint16_t baseTile = state.BgTileSelect ? 0 : 0x1000; - std::fill(outBuffer, outBuffer + 1024*256, 0xFFFFFFFF); + std::fill(outBuffer, outBuffer + 1024 * 256, 0xFFFFFFFF); uint16_t vramMask = isCgb ? 0x3FFF : 0x1FFF; - for(int row = 0; row < 32; row++) { + for (int row = 0; row < 32; row++) + { uint16_t baseOffset = offset + ((row & 0x1F) << 5); - for(int column = 0; column < 32; column++) { + for (int column = 0; column < 32; column++) + { uint16_t addr = (baseOffset + column); uint8_t tileIndex = vram[addr]; @@ -399,26 +490,31 @@ void PpuTools::GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offs bool vMirror = (attributes & 0x40) != 0; //bool bgPriority = (attributes & 0x80) != 0; - uint16_t tileStart = baseTile + (baseTile ? (int8_t)tileIndex*16 : tileIndex*16); + uint16_t tileStart = baseTile + (baseTile ? (int8_t)tileIndex * 16 : tileIndex * 16); tileStart |= tileBank; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { uint16_t pixelStart = tileStart + (vMirror ? (7 - y) : y) * 2; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, vramMask, 2, pixelStart, shift); - outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = DefaultVideoFilter::ToArgb(state.CgbBgPalettes[bgPalette + color]); + outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = DefaultVideoFilter::ToArgb( + state.CgbBgPalettes[bgPalette + color]); } } } } } -void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* outBuffer) +void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, + uint8_t* oamRam, uint32_t* outBuffer) { std::fill(outBuffer, outBuffer + 256 * 256, 0xFF333311); - for(int i = 16; i < 16 + 144; i++) { + for (int i = 16; i < 16 + 144; i++) + { std::fill(outBuffer + i * 256 + 8, outBuffer + i * 256 + 168, 0xFF888866); } @@ -428,12 +524,15 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta constexpr uint8_t width = 8; uint8_t filled[256]; - for(int row = 0; row < 256; row++) { + for (int row = 0; row < 256; row++) + { std::fill(filled, filled + 256, 0xFF); - for(int i = 0; i < 0xA0; i += 4) { + for (int i = 0; i < 0xA0; i += 4) + { uint8_t sprY = oamRam[i]; - if(sprY > row || sprY + height <= row) { + if (sprY > row || sprY + height <= row) + { continue; } @@ -447,7 +546,8 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta bool hMirror = (attributes & 0x20) != 0; bool vMirror = (attributes & 0x40) != 0; - if(largeSprites) { + if (largeSprites) + { tileIndex &= 0xFE; } @@ -455,18 +555,24 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta tileStart |= tileBank; uint16_t pixelStart = tileStart + (vMirror ? (height - 1 - y) : y) * 2; - for(int x = 0; x < width; x++) { - if(sprX + x >= 256) { + for (int x = 0; x < width; x++) + { + if (sprX + x >= 256) + { break; - } else if(filled[sprX + x] < sprX) { + } + else if (filled[sprX + x] < sprX) + { continue; } uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, 0x3FFF, 2, pixelStart, shift); - if(color > 0) { - if(!isCgb) { + if (color > 0) + { + if (!isCgb) + { color = (((attributes & 0x10) ? state.ObjPalette1 : state.ObjPalette0) >> (color * 2)) & 0x03; } @@ -477,4 +583,4 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta } } } -} \ No newline at end of file +} diff --git a/Core/PpuTools.h b/Core/PpuTools.h index bf0a59a..b9da4e4 100644 --- a/Core/PpuTools.h +++ b/Core/PpuTools.h @@ -17,38 +17,46 @@ struct ViewerRefreshConfig class PpuTools { private: - Ppu *_ppu; - Console *_console; + Ppu* _ppu; + Console* _console; unordered_map _updateTimings; - uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift); + uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, + const uint8_t shift); void BlendColors(uint8_t output[4], uint8_t input[4]); - uint32_t GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, uint16_t basePaletteOffset); + uint32_t GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, + uint16_t basePaletteOffset); public: - PpuTools(Console *console, Ppu *ppu); + PpuTools(Console* console, Ppu* ppu); - void GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint8_t *cgram, uint32_t *outBuffer); - void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t *outBuffer); - void GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, uint8_t* cgram, uint32_t *outBuffer); + void GetTileView(GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint8_t* cgram, uint32_t* outBuffer); + void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t* outBuffer); + void GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, + uint8_t* cgram, uint32_t* outBuffer); void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType); void RemoveViewer(uint32_t viewerId); - + __forceinline void UpdateViewers(uint16_t scanline, uint16_t cycle, CpuType cpuType) { - if(_updateTimings.size() > 0) { - for(auto updateTiming : _updateTimings) { + if (_updateTimings.size() > 0) + { + for (auto updateTiming : _updateTimings) + { ViewerRefreshConfig cfg = updateTiming.second; - if(cfg.Cycle == cycle && cfg.Scanline == scanline && cfg.Type == cpuType) { - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first); + if (cfg.Cycle == cycle && cfg.Scanline == scanline && cfg.Type == cpuType) + { + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, + (void*)(uint64_t)updateTiming.first); } } } } void GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offset, uint32_t* outBuffer); - void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* outBuffer); -}; \ No newline at end of file + void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, + uint32_t* outBuffer); +}; diff --git a/Core/PpuTypes.h b/Core/PpuTypes.h index 9c85bb1..1a96bd9 100644 --- a/Core/PpuTypes.h +++ b/Core/PpuTypes.h @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -enum class WindowMaskLogic +enum class WindowMaskLogic { Or = 0, And = 1, @@ -36,7 +36,8 @@ struct SpriteInfo bool IsVisible(uint16_t scanline, bool interlace) { - if(X != -256 && (X + Width <= 0 || X > 255)) { + if (X != -256 && (X + Width <= 0 || X > 255)) + { //Sprite is not visible (and must be ignored for time/range flag calculations) //Sprites at X=-256 are always used when considering Time/Range flag calculations, but not actually drawn. return false; @@ -83,7 +84,7 @@ struct Mode7Config int16_t CenterY; uint8_t ValueLatch; - + bool LargeMap; bool FillWithTile0; bool HorizontalMirroring; @@ -101,19 +102,28 @@ struct WindowConfig uint8_t Left; uint8_t Right; - template + template bool PixelNeedsMasking(int x) { - if(InvertedLayers[layerIndex]) { - if(Left > Right) { + if (InvertedLayers[layerIndex]) + { + if (Left > Right) + { return true; - } else { + } + else + { return x < Left || x > Right; } - } else { - if(Left > Right) { + } + else + { + if (Left > Right) + { return false; - } else { + } + else + { return x >= Left && x <= Right; } } @@ -187,4 +197,4 @@ struct PpuState enum PixelFlags { AllowColorMath = 0x80, -}; \ No newline at end of file +}; diff --git a/Core/Profiler.cpp b/Core/Profiler.cpp index bcd2a3e..0d09e4f 100644 --- a/Core/Profiler.cpp +++ b/Core/Profiler.cpp @@ -20,11 +20,13 @@ Profiler::~Profiler() { } -void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag) +void Profiler::StackFunction(AddressInfo& addr, StackFrameFlags stackFlag) { - if(addr.Address >= 0) { + if (addr.Address >= 0) + { uint32_t key = addr.Address | ((uint8_t)addr.Type << 24); - if(_functions.find(key) == _functions.end()) { + if (_functions.find(key) == _functions.end()) + { _functions[key] = ProfiledFunction(); _functions[key].Address = addr; } @@ -46,16 +48,18 @@ void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag) void Profiler::UpdateCycles() { uint64_t masterClock = _console->GetMasterClock(); - + ProfiledFunction& func = _functions[_currentFunction]; uint64_t clockGap = masterClock - _prevMasterClock; func.ExclusiveCycles += clockGap; func.InclusiveCycles += clockGap; - + int32_t len = (int32_t)_functionStack.size(); - for(int32_t i = len - 1; i >= 0; i--) { + for (int32_t i = len - 1; i >= 0; i--) + { _functions[_functionStack[i]].InclusiveCycles += clockGap; - if(_stackFlags[i] != StackFrameFlags::None) { + if (_stackFlags[i] != StackFrameFlags::None) + { //Don't apply inclusive times to stack frames before an IRQ/NMI break; } @@ -67,7 +71,8 @@ void Profiler::UpdateCycles() void Profiler::UnstackFunction() { - if(!_functionStack.empty()) { + if (!_functionStack.empty()) + { UpdateCycles(); //Return to the previous function @@ -99,24 +104,26 @@ void Profiler::InternalReset() _functionStack.clear(); _stackFlags.clear(); _cycleCountStack.clear(); - + _functions.clear(); _functions[ResetFunctionIndex] = ProfiledFunction(); - _functions[ResetFunctionIndex].Address = { ResetFunctionIndex, SnesMemoryType::Register }; + _functions[ResetFunctionIndex].Address = {ResetFunctionIndex, SnesMemoryType::Register}; } void Profiler::GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount) { DebugBreakHelper helper(_debugger); - + UpdateCycles(); functionCount = 0; - for(auto func : _functions) { + for (auto func : _functions) + { profilerData[functionCount] = func.second; functionCount++; - if(functionCount >= 100000) { + if (functionCount >= 100000) + { break; } } diff --git a/Core/Profiler.h b/Core/Profiler.h index 4cbb0cb..da86bee 100644 --- a/Core/Profiler.h +++ b/Core/Profiler.h @@ -22,7 +22,7 @@ private: Console* _console; unordered_map _functions; - + deque _functionStack; deque _stackFlags; deque _cycleCountStack; @@ -43,4 +43,4 @@ public: void Reset(); void GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount); -}; \ No newline at end of file +}; diff --git a/Core/RamHandler.h b/Core/RamHandler.h index 2c694e2..9f165df 100644 --- a/Core/RamHandler.h +++ b/Core/RamHandler.h @@ -6,21 +6,24 @@ class RamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; uint32_t _mask; protected: uint32_t _offset; public: - RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType) : IMemoryHandler(memoryType) + RamHandler(uint8_t* ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType) : IMemoryHandler(memoryType) { _ram = ram + offset; _offset = offset; - if(size - offset < 0x1000) { + if (size - offset < 0x1000) + { _mask = size - offset - 1; - } else { + } + else + { _mask = 0xFFF; } _memoryType = memoryType; @@ -36,13 +39,17 @@ public: return _ram[addr & _mask]; } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - if(_mask != 0xFFF) { - for(int i = 0; i < 0x1000; i++) { + if (_mask != 0xFFF) + { + for (int i = 0; i < 0x1000; i++) + { output[i] = _ram[i & _mask]; } - } else { + } + else + { memcpy(output, _ram, 0x1000); } } @@ -59,4 +66,4 @@ public: info.Type = _memoryType; return info; } -}; \ No newline at end of file +}; diff --git a/Core/RecordedRomTest.cpp b/Core/RecordedRomTest.cpp index 030930a..8521cc5 100644 --- a/Core/RecordedRomTest.cpp +++ b/Core/RecordedRomTest.cpp @@ -17,9 +17,12 @@ RecordedRomTest::RecordedRomTest(shared_ptr console) { - if(console) { + if (console) + { _console = console; - } else { + } + else + { _console.reset(new Console()); _console->Initialize(); } @@ -39,15 +42,19 @@ void RecordedRomTest::SaveFrame() uint16_t* ppuFrameBuffer = _ppu->GetScreenBuffer(); uint8_t md5Hash[16]; - GetMd5Sum(md5Hash, ppuFrameBuffer, width*height*sizeof(uint16_t)); + GetMd5Sum(md5Hash, ppuFrameBuffer, width * height * sizeof(uint16_t)); - if(memcmp(_previousHash, md5Hash, 16) == 0 && _currentCount < 255) { + if (memcmp(_previousHash, md5Hash, 16) == 0 && _currentCount < 255) + { _currentCount++; - } else { + } + else + { uint8_t* hash = new uint8_t[16]; memcpy(hash, md5Hash, 16); _screenshotHashes.push_back(hash); - if(_currentCount > 0) { + if (_currentCount > 0) + { _repetitionCount.push_back(_currentCount); } _currentCount = 1; @@ -68,19 +75,22 @@ void RecordedRomTest::ValidateFrame() uint8_t md5Hash[16]; GetMd5Sum(md5Hash, ppuFrameBuffer, width * height * sizeof(uint16_t)); - if(_currentCount == 0) { + if (_currentCount == 0) + { _currentCount = _repetitionCount.front(); _repetitionCount.pop_front(); _screenshotHashes.pop_front(); } _currentCount--; - if(memcmp(_screenshotHashes.front(), md5Hash, 16) != 0) { + if (memcmp(_screenshotHashes.front(), md5Hash, 16) != 0) + { _badFrameCount++; //_console->BreakIfDebugging(); - } - - if(_currentCount == 0 && _repetitionCount.empty()) { + } + + if (_currentCount == 0 && _repetitionCount.empty()) + { //End of test _runningTest = false; _signal.Signal(); @@ -89,28 +99,33 @@ void RecordedRomTest::ValidateFrame() void RecordedRomTest::ProcessNotification(ConsoleNotificationType type, void* parameter) { - switch(type) { - case ConsoleNotificationType::PpuFrameDone: - if(_recording) { - SaveFrame(); - } else if(_runningTest) { - ValidateFrame(); - } - break; - - default: - break; + switch (type) + { + case ConsoleNotificationType::PpuFrameDone: + if (_recording) + { + SaveFrame(); + } + else if (_runningTest) + { + ValidateFrame(); + } + break; + + default: + break; } } void RecordedRomTest::Reset() { memset(_previousHash, 0xFF, 16); - + _currentCount = 0; _repetitionCount.clear(); - for(uint8_t* hash : _screenshotHashes) { + for (uint8_t* hash : _screenshotHashes) + { delete[] hash; } _screenshotHashes.clear(); @@ -125,10 +140,12 @@ void RecordedRomTest::Record(string filename, bool reset) _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); _filename = filename; - string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), FolderUtilities::GetFilename(filename, false) + ".mrt"); + string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), + FolderUtilities::GetFilename(filename, false) + ".mrt"); _file.open(mrtFilename, ios::out | ios::binary); - if(_file) { + if (_file) + { _console->Lock(); Reset(); @@ -139,10 +156,11 @@ void RecordedRomTest::Record(string filename, bool reset) EmulationConfig emuCfg = _console->GetSettings()->GetEmulationConfig(); emuCfg.RamPowerOnState = RamState::AllZeros; _console->GetSettings()->SetEmulationConfig(emuCfg); - + //Start recording movie alongside with screenshots RecordMovieOptions options; - string movieFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), FolderUtilities::GetFilename(filename, false) + ".mmo"); + string movieFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), + FolderUtilities::GetFilename(filename, false) + ".mmo"); memcpy(options.Filename, movieFilename.c_str(), std::max(1000, (int)movieFilename.size())); options.RecordFrom = reset ? RecordMovieFrom::StartWithSaveData : RecordMovieFrom::CurrentState; _console->GetMovieManager()->Record(options); @@ -159,30 +177,33 @@ int32_t RecordedRomTest::Run(string filename) EmuSettings* settings = _console->GetSettings().get(); string testName = FolderUtilities::GetFilename(filename, false); - + VirtualFile testMovie(filename, "TestMovie.msm"); VirtualFile testRom(filename, "TestRom.sfc"); ZipReader zipReader; zipReader.LoadArchive(filename); - + stringstream testData; zipReader.GetStream("TestData.mrt", testData); - if(testData && testMovie.IsValid() && testRom.IsValid()) { + if (testData && testMovie.IsValid() && testRom.IsValid()) + { char header[3]; testData.read((char*)&header, 3); - if(memcmp((char*)&header, "MRT", 3) != 0) { + if (memcmp((char*)&header, "MRT", 3) != 0) + { //Invalid test file return false; } - + Reset(); uint32_t hashCount; testData.read((char*)&hashCount, sizeof(uint32_t)); - - for(uint32_t i = 0; i < hashCount; i++) { + + for (uint32_t i = 0; i < hashCount; i++) + { uint8_t repeatCount = 0; testData.read((char*)&repeatCount, sizeof(uint8_t)); _repetitionCount.push_back(repeatCount); @@ -205,18 +226,21 @@ int32_t RecordedRomTest::Run(string filename) _console->Lock(); //Start playing movie - if(_console->LoadRom(testRom, VirtualFile(""))) { + if (_console->LoadRom(testRom, VirtualFile(""))) + { settings->SetFlag(EmulationFlags::MaximumSpeed); _console->GetMovieManager()->Play(testMovie, true); _ppu = _console->GetPpu().get(); - + _runningTest = true; _console->Unlock(); _signal.Wait(); _console->Stop(false); _runningTest = false; - } else { + } + else + { //Something went wrong when loading the rom _console->Unlock(); return -2; @@ -232,7 +256,8 @@ int32_t RecordedRomTest::Run(string filename) void RecordedRomTest::Stop() { - if(_recording) { + if (_recording) + { Save(); } Reset(); @@ -252,8 +277,9 @@ void RecordedRomTest::Save() uint32_t hashCount = (uint32_t)_screenshotHashes.size(); _file.write((char*)&hashCount, sizeof(uint32_t)); - - for(uint32_t i = 0; i < hashCount; i++) { + + for (uint32_t i = 0; i < hashCount; i++) + { _file.write((char*)&_repetitionCount[i], sizeof(uint8_t)); _file.write((char*)&_screenshotHashes[i][0], 16); } @@ -263,17 +289,19 @@ void RecordedRomTest::Save() ZipWriter writer; writer.Initialize(_filename); - string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), FolderUtilities::GetFilename(_filename, false) + ".mrt"); + string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), + FolderUtilities::GetFilename(_filename, false) + ".mrt"); writer.AddFile(mrtFilename, "TestData.mrt"); std::remove(mrtFilename.c_str()); - string mmoFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), FolderUtilities::GetFilename(_filename, false) + ".mmo"); + string mmoFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), + FolderUtilities::GetFilename(_filename, false) + ".mmo"); writer.AddFile(mmoFilename, "TestMovie.msm"); std::remove(mmoFilename.c_str()); writer.AddFile(_console->GetCartridge()->GetRomInfo().RomFile.GetFilePath(), "TestRom.sfc"); - + writer.Save(); MessageManager::DisplayMessage("Test", "TestFileSavedTo", FolderUtilities::GetFilename(_filename, true)); -} \ No newline at end of file +} diff --git a/Core/RecordedRomTest.h b/Core/RecordedRomTest.h index 59fc28a..ca8b15a 100644 --- a/Core/RecordedRomTest.h +++ b/Core/RecordedRomTest.h @@ -23,7 +23,7 @@ private: std::deque _screenshotHashes; std::deque _repetitionCount; uint8_t _currentCount = 0; - + string _filename; ofstream _file; @@ -43,4 +43,4 @@ public: void Record(string filename, bool reset); int32_t Run(string filename); void Stop(); -}; \ No newline at end of file +}; diff --git a/Core/RegisterHandlerA.h b/Core/RegisterHandlerA.h index 68978b8..d4406ca 100644 --- a/Core/RegisterHandlerA.h +++ b/Core/RegisterHandlerA.h @@ -8,12 +8,13 @@ class RegisterHandlerA : public IMemoryHandler { private: - DmaController *_dmaController; - InternalRegisters *_regs; - ControlManager *_controlManager; + DmaController* _dmaController; + InternalRegisters* _regs; + ControlManager* _controlManager; public: - RegisterHandlerA(DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager) : IMemoryHandler(SnesMemoryType::Register) + RegisterHandlerA(DmaController* dmaController, InternalRegisters* regs, + ControlManager* controlManager) : IMemoryHandler(SnesMemoryType::Register) { _regs = regs; _dmaController = dmaController; @@ -23,11 +24,16 @@ public: uint8_t Read(uint32_t addr) override { addr &= 0xFFFF; - if(addr == 0x4016 || addr == 0x4017) { + if (addr == 0x4016 || addr == 0x4017) + { return _controlManager->Read(addr); - } else if(addr >= 0x4300) { + } + else if (addr >= 0x4300) + { return _dmaController->Read(addr); - } else { + } + else + { return _regs->Read(addr); } } @@ -35,17 +41,22 @@ public: uint8_t Peek(uint32_t addr) override { addr &= 0xFFFF; - if(addr == 0x4016 || addr == 0x4017) { + if (addr == 0x4016 || addr == 0x4017) + { //Avoid side effects for now return 0; - } else if(addr >= 0x4300) { + } + else if (addr >= 0x4300) + { return _dmaController->Read(addr); - } else { + } + else + { return _regs->Peek(addr); } } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { //Avoid side effects for now memset(output, 0, 0x1000); @@ -54,17 +65,22 @@ public: void Write(uint32_t addr, uint8_t value) override { addr &= 0xFFFF; - if(addr == 0x4016) { + if (addr == 0x4016) + { return _controlManager->Write(addr, value); - } else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) { + } + else if (addr == 0x420B || addr == 0x420C || addr >= 0x4300) + { _dmaController->Write(addr, value); - } else { + } + else + { _regs->Write(addr, value); } } AddressInfo GetAbsoluteAddress(uint32_t address) override { - return { -1, SnesMemoryType::CpuMemory }; + return {-1, SnesMemoryType::CpuMemory}; } }; diff --git a/Core/RegisterHandlerB.cpp b/Core/RegisterHandlerB.cpp index 3344585..77ed3e2 100644 --- a/Core/RegisterHandlerB.cpp +++ b/Core/RegisterHandlerB.cpp @@ -9,7 +9,8 @@ #include "CheatManager.h" #include "../Utilities/Serializer.h" -RegisterHandlerB::RegisterHandlerB(Console *console, Ppu * ppu, Spc * spc, uint8_t * workRam) : IMemoryHandler(SnesMemoryType::Register) +RegisterHandlerB::RegisterHandlerB(Console* console, Ppu* ppu, Spc* spc, uint8_t* workRam) : IMemoryHandler( + SnesMemoryType::Register) { _console = console; _cheatManager = console->GetCheatManager().get(); @@ -24,19 +25,28 @@ RegisterHandlerB::RegisterHandlerB(Console *console, Ppu * ppu, Spc * spc, uint8 uint8_t RegisterHandlerB::Read(uint32_t addr) { addr &= 0xFFFF; - if(addr >= 0x2140 && addr <= 0x217F) { + if (addr >= 0x2140 && addr <= 0x217F) + { return _spc->CpuReadRegister(addr & 0x03); - } else if(addr == 0x2180) { + } + else if (addr == 0x2180) + { uint8_t value = _workRam[_wramPosition]; _console->ProcessWorkRamRead(_wramPosition, value); _console->GetCheatManager()->ApplyCheat(0x7E0000 | _wramPosition, value); _wramPosition = (_wramPosition + 1) & 0x1FFFF; return value; - } else if(addr >= 0x2300 && addr <= 0x23FF && _console->GetCartridge()->GetSa1()) { + } + else if (addr >= 0x2300 && addr <= 0x23FF && _console->GetCartridge()->GetSa1()) + { return _console->GetCartridge()->GetSa1()->CpuRegisterRead(addr); - } else if(_msu1 && addr <= 0x2007) { + } + else if (_msu1 && addr <= 0x2007) + { return _msu1->Read(addr); - } else { + } + else + { return _ppu->Read(addr); } } @@ -47,7 +57,7 @@ uint8_t RegisterHandlerB::Peek(uint32_t addr) return 0; } -void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t *output) +void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t* output) { //Avoid side effects for now memset(output, 0, 0x1000); @@ -56,35 +66,48 @@ void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t *output) void RegisterHandlerB::Write(uint32_t addr, uint8_t value) { addr &= 0xFFFF; - if(addr >= 0x2140 && addr <= 0x217F) { + if (addr >= 0x2140 && addr <= 0x217F) + { return _spc->CpuWriteRegister(addr & 0x03, value); - } if(addr >= 0x2180 && addr <= 0x2183) { - switch(addr & 0xFFFF) { - case 0x2180: - _console->ProcessWorkRamWrite(_wramPosition, value); - _workRam[_wramPosition] = value; - _wramPosition = (_wramPosition + 1) & 0x1FFFF; - break; + } + if (addr >= 0x2180 && addr <= 0x2183) + { + switch (addr & 0xFFFF) + { + case 0x2180: + _console->ProcessWorkRamWrite(_wramPosition, value); + _workRam[_wramPosition] = value; + _wramPosition = (_wramPosition + 1) & 0x1FFFF; + break; - case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break; - case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break; - case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break; + case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; + break; + case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); + break; + case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); + break; } - } else if(addr >= 0x2200 && addr <= 0x22FF && _console->GetCartridge()->GetSa1()) { + } + else if (addr >= 0x2200 && addr <= 0x22FF && _console->GetCartridge()->GetSa1()) + { _console->GetCartridge()->GetSa1()->CpuRegisterWrite(addr, value); - } else if(_msu1 && addr <= 0x2007) { + } + else if (_msu1 && addr <= 0x2007) + { return _msu1->Write(addr, value); - } else { + } + else + { _ppu->Write(addr, value); } } AddressInfo RegisterHandlerB::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::CpuMemory }; + return {-1, SnesMemoryType::CpuMemory}; } -void RegisterHandlerB::Serialize(Serializer &s) +void RegisterHandlerB::Serialize(Serializer& s) { s.Stream(_wramPosition); } diff --git a/Core/RegisterHandlerB.h b/Core/RegisterHandlerB.h index ba48b6f..33e41ac 100644 --- a/Core/RegisterHandlerB.h +++ b/Core/RegisterHandlerB.h @@ -13,25 +13,25 @@ class CheatManager; class RegisterHandlerB : public IMemoryHandler, public ISerializable { private: - Console *_console; - CheatManager *_cheatManager; - Ppu *_ppu; - Spc *_spc; - Sa1 *_sa1; - Msu1 *_msu1; + Console* _console; + CheatManager* _cheatManager; + Ppu* _ppu; + Spc* _spc; + Sa1* _sa1; + Msu1* _msu1; - uint8_t *_workRam; + uint8_t* _workRam; uint32_t _wramPosition; public: - RegisterHandlerB(Console *console, Ppu *ppu, Spc *spc, uint8_t *workRam); + RegisterHandlerB(Console* console, Ppu* ppu, Spc* spc, uint8_t* workRam); uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/RewindData.cpp b/Core/RewindData.cpp index 61527f7..73453f7 100644 --- a/Core/RewindData.cpp +++ b/Core/RewindData.cpp @@ -4,14 +4,15 @@ #include "SaveStateManager.h" #include "../Utilities/miniz.h" -void RewindData::GetStateData(stringstream &stateData) +void RewindData::GetStateData(stringstream& stateData) { stateData.write((char*)SaveStateData.data(), SaveStateData.size()); } -void RewindData::LoadState(shared_ptr &console) +void RewindData::LoadState(shared_ptr& console) { - if(SaveStateData.size() > 0) { + if (SaveStateData.size() > 0) + { stringstream stream; stream.write((char*)SaveStateData.data(), SaveStateData.size()); stream.seekg(0, ios::beg); @@ -20,12 +21,12 @@ void RewindData::LoadState(shared_ptr &console) } } -void RewindData::SaveState(shared_ptr &console) +void RewindData::SaveState(shared_ptr& console) { std::stringstream state; console->Serialize(state); string data = state.str(); - SaveStateData = vector(data.c_str(), data.c_str()+data.size()); + SaveStateData = vector(data.c_str(), data.c_str() + data.size()); FrameCount = 0; } diff --git a/Core/RewindData.h b/Core/RewindData.h index a66db76..afc1718 100644 --- a/Core/RewindData.h +++ b/Core/RewindData.h @@ -15,8 +15,8 @@ public: int32_t FrameCount = 0; bool EndOfSegment = false; - void GetStateData(stringstream &stateData); + void GetStateData(stringstream& stateData); - void LoadState(shared_ptr &console); - void SaveState(shared_ptr &console); + void LoadState(shared_ptr& console); + void SaveState(shared_ptr& console); }; diff --git a/Core/RewindManager.cpp b/Core/RewindManager.cpp index 05a1613..186d128 100644 --- a/Core/RewindManager.cpp +++ b/Core/RewindManager.cpp @@ -42,49 +42,61 @@ void RewindManager::ClearBuffer() _currentHistory = RewindData(); } -void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter) +void RewindManager::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(type == ConsoleNotificationType::PpuFrameDone) { + if (type == ConsoleNotificationType::PpuFrameDone) + { _hasHistory = _history.size() >= 2; - if(_settings->GetRewindBufferSize() > 0) { - switch(_rewindState) { - case RewindState::Starting: - case RewindState::Started: - case RewindState::Debugging: - _currentHistory.FrameCount--; - break; + if (_settings->GetRewindBufferSize() > 0) + { + switch (_rewindState) + { + case RewindState::Starting: + case RewindState::Started: + case RewindState::Debugging: + _currentHistory.FrameCount--; + break; - case RewindState::Stopping: - _framesToFastForward--; - _currentHistory.FrameCount++; - if(_framesToFastForward == 0) { - for(int i = 0; i < 4; i++) { - size_t numberToRemove = _currentHistory.InputLogs[i].size(); - _currentHistory.InputLogs[i] = _historyBackup.front().InputLogs[i]; - for(size_t j = 0; j < numberToRemove; j++) { - _currentHistory.InputLogs[i].pop_back(); - } + case RewindState::Stopping: + _framesToFastForward--; + _currentHistory.FrameCount++; + if (_framesToFastForward == 0) + { + for (int i = 0; i < 4; i++) + { + size_t numberToRemove = _currentHistory.InputLogs[i].size(); + _currentHistory.InputLogs[i] = _historyBackup.front().InputLogs[i]; + for (size_t j = 0; j < numberToRemove; j++) + { + _currentHistory.InputLogs[i].pop_back(); } - _historyBackup.clear(); - _rewindState = RewindState::Stopped; - _settings->ClearFlag(EmulationFlags::Rewind); - _settings->ClearFlag(EmulationFlags::MaximumSpeed); } - break; - - case RewindState::Stopped: - _currentHistory.FrameCount++; - break; + _historyBackup.clear(); + _rewindState = RewindState::Stopped; + _settings->ClearFlag(EmulationFlags::Rewind); + _settings->ClearFlag(EmulationFlags::MaximumSpeed); + } + break; + + case RewindState::Stopped: + _currentHistory.FrameCount++; + break; } - } else { + } + else + { ClearBuffer(); } - } else if(type == ConsoleNotificationType::StateLoaded) { - if(_rewindState == RewindState::Stopped) { + } + else if (type == ConsoleNotificationType::StateLoaded) + { + if (_rewindState == RewindState::Stopped) + { //A save state was loaded by the user, mark as the end of the current "segment" (for history viewer) _currentHistory.EndOfSegment = true; } @@ -94,12 +106,15 @@ void RewindManager::ProcessNotification(ConsoleNotificationType type, void * par void RewindManager::AddHistoryBlock() { uint32_t maxHistorySize = _settings->GetRewindBufferSize() * 60 * RewindManager::BufferSize / 60; - if(maxHistorySize > 0) { - while(_history.size() > maxHistorySize) { + if (maxHistorySize > 0) + { + while (_history.size() > maxHistorySize) + { _history.pop_front(); } - if(_currentHistory.FrameCount > 0) { + if (_currentHistory.FrameCount > 0) + { _history.push_back(_currentHistory); } _currentHistory = RewindData(); @@ -109,17 +124,22 @@ void RewindManager::AddHistoryBlock() void RewindManager::PopHistory() { - if(_history.empty() && _currentHistory.FrameCount <= 0) { + if (_history.empty() && _currentHistory.FrameCount <= 0) + { StopRewinding(); - } else { - if(_currentHistory.FrameCount <= 0) { + } + else + { + if (_currentHistory.FrameCount <= 0) + { _currentHistory = _history.back(); _history.pop_back(); } _historyBackup.push_front(_currentHistory); _currentHistory.LoadState(_console); - if(!_audioHistoryBuilder.empty()) { + if (!_audioHistoryBuilder.empty()) + { _audioHistory.insert(_audioHistory.begin(), _audioHistoryBuilder.begin(), _audioHistoryBuilder.end()); _audioHistoryBuilder.clear(); } @@ -128,7 +148,8 @@ void RewindManager::PopHistory() void RewindManager::Start(bool forDebugger) { - if(_rewindState == RewindState::Stopped && _settings->GetRewindBufferSize() > 0) { + if (_rewindState == RewindState::Stopped && _settings->GetRewindBufferSize() > 0) + { auto lock = _console->AcquireLock(); _rewindState = forDebugger ? RewindState::Debugging : RewindState::Starting; @@ -137,7 +158,7 @@ void RewindManager::Start(bool forDebugger) _audioHistoryBuilder.clear(); _audioHistory.clear(); _historyBackup.clear(); - + PopHistory(); _console->GetSoundMixer()->StopAudio(true); _settings->SetFlag(EmulationFlags::MaximumSpeed); @@ -147,8 +168,10 @@ void RewindManager::Start(bool forDebugger) void RewindManager::ForceStop() { - if(_rewindState != RewindState::Stopped) { - while(_historyBackup.size() > 1) { + if (_rewindState != RewindState::Stopped) + { + while (_historyBackup.size() > 1) + { _history.push_back(_historyBackup.front()); _historyBackup.pop_front(); } @@ -162,25 +185,32 @@ void RewindManager::ForceStop() void RewindManager::Stop() { - if(_rewindState >= RewindState::Starting) { + if (_rewindState >= RewindState::Starting) + { auto lock = _console->AcquireLock(); - if(_rewindState == RewindState::Started) { + if (_rewindState == RewindState::Started) + { //Move back to the save state containing the frame currently shown on the screen - if(_historyBackup.size() > 1) { + if (_historyBackup.size() > 1) + { _framesToFastForward = (uint32_t)_videoHistory.size() + _historyBackup.front().FrameCount; - do { + do + { _history.push_back(_historyBackup.front()); _framesToFastForward -= _historyBackup.front().FrameCount; _historyBackup.pop_front(); _currentHistory = _historyBackup.front(); } - while(_framesToFastForward > RewindManager::BufferSize && _historyBackup.size() > 1); + while (_framesToFastForward > RewindManager::BufferSize && _historyBackup.size() > 1); } - } else { + } + else + { //We started rewinding, but didn't actually visually rewind anything yet //Move back to the save state containing the frame currently shown on the screen - while(_historyBackup.size() > 1) { + while (_historyBackup.size() > 1) + { _history.push_back(_historyBackup.front()); _historyBackup.pop_front(); } @@ -189,11 +219,14 @@ void RewindManager::Stop() } _currentHistory.LoadState(_console); - if(_framesToFastForward > 0) { + if (_framesToFastForward > 0) + { _rewindState = RewindState::Stopping; _currentHistory.FrameCount = 0; _settings->SetFlag(EmulationFlags::MaximumSpeed); - } else { + } + else + { _rewindState = RewindState::Stopped; _historyBackup.clear(); _settings->ClearFlag(EmulationFlags::MaximumSpeed); @@ -209,21 +242,27 @@ void RewindManager::Stop() void RewindManager::ProcessEndOfFrame() { - if(_rewindState >= RewindState::Starting) { - if(_currentHistory.FrameCount <= 0 && _rewindState != RewindState::Debugging) { + if (_rewindState >= RewindState::Starting) + { + if (_currentHistory.FrameCount <= 0 && _rewindState != RewindState::Debugging) + { //If we're debugging, we want to keep running the emulation to the end of the next frame (even if it's incomplete) //Otherwise the emulation might diverge due to missing inputs. PopHistory(); } - } else if(_currentHistory.FrameCount >= RewindManager::BufferSize) { + } + else if (_currentHistory.FrameCount >= RewindManager::BufferSize) + { AddHistoryBlock(); } } -void RewindManager::ProcessFrame(void * frameBuffer, uint32_t width, uint32_t height, bool forRewind) +void RewindManager::ProcessFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind) { - if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) { - if(!forRewind) { + if (_rewindState == RewindState::Starting || _rewindState == RewindState::Started) + { + if (!forRewind) + { //Ignore any frames that occur between start of rewind process & first rewinded frame completed //These are caused by the fact that VideoDecoder is asynchronous - a previous (extra) frame can end up //in the rewind queue, which causes display glitches @@ -236,71 +275,93 @@ void RewindManager::ProcessFrame(void * frameBuffer, uint32_t width, uint32_t he newFrame.Height = height; _videoHistoryBuilder.push_back(newFrame); - if(_videoHistoryBuilder.size() == (size_t)_historyBackup.front().FrameCount) { - for(int i = (int)_videoHistoryBuilder.size() - 1; i >= 0; i--) { + if (_videoHistoryBuilder.size() == (size_t)_historyBackup.front().FrameCount) + { + for (int i = (int)_videoHistoryBuilder.size() - 1; i >= 0; i--) + { _videoHistory.push_front(_videoHistoryBuilder[i]); } _videoHistoryBuilder.clear(); } - if(_rewindState == RewindState::Started || _videoHistory.size() >= RewindManager::BufferSize) { + if (_rewindState == RewindState::Started || _videoHistory.size() >= RewindManager::BufferSize) + { _rewindState = RewindState::Started; _settings->ClearFlag(EmulationFlags::MaximumSpeed); - if(!_videoHistory.empty()) { - VideoFrame &frameData = _videoHistory.back(); + if (!_videoHistory.empty()) + { + VideoFrame& frameData = _videoHistory.back(); _console->GetVideoRenderer()->UpdateFrame(frameData.Data.data(), frameData.Width, frameData.Height); _videoHistory.pop_back(); } } - } else if(_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) { + } + else if (_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) + { //Display nothing while resyncing - } else { + } + else + { _console->GetVideoRenderer()->UpdateFrame(frameBuffer, width, height); } } -bool RewindManager::ProcessAudio(int16_t * soundBuffer, uint32_t sampleCount) +bool RewindManager::ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount) { - if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) { + if (_rewindState == RewindState::Starting || _rewindState == RewindState::Started) + { _audioHistoryBuilder.insert(_audioHistoryBuilder.end(), soundBuffer, soundBuffer + sampleCount * 2); - if(_rewindState == RewindState::Started && _audioHistory.size() > sampleCount * 2) { - for(uint32_t i = 0; i < sampleCount * 2; i++) { + if (_rewindState == RewindState::Started && _audioHistory.size() > sampleCount * 2) + { + for (uint32_t i = 0; i < sampleCount * 2; i++) + { soundBuffer[i] = _audioHistory.back(); _audioHistory.pop_back(); } return true; - } else { + } + else + { //Mute while we prepare to rewind return false; } - } else if(_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) { + } + else if (_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) + { //Mute while we resync return false; - } else { + } + else + { return true; } } void RewindManager::RecordInput(vector> devices) { - if(_settings->GetRewindBufferSize() > 0 && _rewindState == RewindState::Stopped) { - for(shared_ptr &device : devices) { + if (_settings->GetRewindBufferSize() > 0 && _rewindState == RewindState::Stopped) + { + for (shared_ptr& device : devices) + { _currentHistory.InputLogs[device->GetPort()].push_back(device->GetRawState()); } } } -bool RewindManager::SetInput(BaseControlDevice *device) +bool RewindManager::SetInput(BaseControlDevice* device) { uint8_t port = device->GetPort(); - if(!_currentHistory.InputLogs[port].empty() && IsRewinding()) { + if (!_currentHistory.InputLogs[port].empty() && IsRewinding()) + { ControlDeviceState state = _currentHistory.InputLogs[port].front(); _currentHistory.InputLogs[port].pop_front(); device->SetRawState(state); return true; - } else { + } + else + { return false; } } @@ -312,9 +373,12 @@ void RewindManager::StartRewinding(bool forDebugger) void RewindManager::StopRewinding(bool forDebugger) { - if(forDebugger) { + if (forDebugger) + { ForceStop(); - } else { + } + else + { Stop(); } } @@ -331,15 +395,20 @@ bool RewindManager::IsStepBack() void RewindManager::RewindSeconds(uint32_t seconds) { - if(_rewindState == RewindState::Stopped) { + if (_rewindState == RewindState::Stopped) + { uint32_t removeCount = (seconds * 60 / RewindManager::BufferSize) + 1; auto lock = _console->AcquireLock(); - for(uint32_t i = 0; i < removeCount; i++) { - if(!_history.empty()) { + for (uint32_t i = 0; i < removeCount; i++) + { + if (!_history.empty()) + { _currentHistory = _history.back(); _history.pop_back(); - } else { + } + else + { break; } } @@ -352,12 +421,12 @@ bool RewindManager::HasHistory() return _hasHistory; } -void RewindManager::SendFrame(void * frameBuffer, uint32_t width, uint32_t height, bool forRewind) +void RewindManager::SendFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind) { ProcessFrame(frameBuffer, width, height, forRewind); } -bool RewindManager::SendAudio(int16_t * soundBuffer, uint32_t sampleCount) +bool RewindManager::SendAudio(int16_t* soundBuffer, uint32_t sampleCount) { return ProcessAudio(soundBuffer, sampleCount); } diff --git a/Core/RewindManager.h b/Core/RewindManager.h index c186ec0..bcf1696 100644 --- a/Core/RewindManager.h +++ b/Core/RewindManager.h @@ -33,7 +33,7 @@ private: shared_ptr _console; shared_ptr _settings; - + bool _hasHistory; std::deque _history; @@ -55,9 +55,9 @@ private: void Stop(); void ForceStop(); - void ProcessFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind); - bool ProcessAudio(int16_t *soundBuffer, uint32_t sampleCount); - + void ProcessFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind); + bool ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount); + void ClearBuffer(); public: @@ -68,7 +68,7 @@ public: void ProcessEndOfFrame(); void RecordInput(vector> devices) override; - bool SetInput(BaseControlDevice *device) override; + bool SetInput(BaseControlDevice* device) override; void StartRewinding(bool forDebugger = false); void StopRewinding(bool forDebugger = false); @@ -78,7 +78,7 @@ public: bool HasHistory(); - void SendFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind); - bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount); + void SendFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind); + bool SendAudio(int16_t* soundBuffer, uint32_t sampleCount); void CopyHistory(shared_ptr destHistoryViewer); -}; \ No newline at end of file +}; diff --git a/Core/RomFinder.h b/Core/RomFinder.h index 61f7593..b36d7af 100644 --- a/Core/RomFinder.h +++ b/Core/RomFinder.h @@ -10,13 +10,15 @@ class RomFinder public: static bool LoadMatchingRom(Console* console, string romName, string sha1Hash) { - if(console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) { + if (console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) + { //Current game matches return true; } string match = FindMatchingRom(console, romName, sha1Hash); - if(!match.empty()) { + if (!match.empty()) + { return console->LoadRom(match, VirtualFile("")); } return false; @@ -24,7 +26,8 @@ public: static string FindMatchingRom(Console* console, string romName, string sha1Hash) { - if(console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) { + if (console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) + { //Current game matches return console->GetRomInfo().RomFile; } @@ -34,11 +37,15 @@ public: std::transform(romName.begin(), romName.end(), romName.begin(), ::tolower); vector romFiles; - for(string folder : FolderUtilities::GetKnownGameFolders()) { - for(string romFilename : FolderUtilities::GetFilesInFolder(folder, VirtualFile::RomExtensions, true)) { + for (string folder : FolderUtilities::GetKnownGameFolders()) + { + for (string romFilename : FolderUtilities::GetFilesInFolder(folder, VirtualFile::RomExtensions, true)) + { string lcRomFile = romFilename; std::transform(lcRomFile.begin(), lcRomFile.end(), lcRomFile.begin(), ::tolower); - if(FolderUtilities::GetFilename(romName, false) == FolderUtilities::GetFilename(lcRomFile, false) && VirtualFile(romFilename).GetSha1Hash() == sha1Hash) { + if (FolderUtilities::GetFilename(romName, false) == FolderUtilities::GetFilename(lcRomFile, false) && + VirtualFile(romFilename).GetSha1Hash() == sha1Hash) + { return romFilename; } } @@ -46,4 +53,4 @@ public: return ""; } -}; \ No newline at end of file +}; diff --git a/Core/RomHandler.h b/Core/RomHandler.h index 822d0d2..b6d6064 100644 --- a/Core/RomHandler.h +++ b/Core/RomHandler.h @@ -10,4 +10,4 @@ public: void Write(uint32_t addr, uint8_t value) override { } -}; \ No newline at end of file +}; diff --git a/Core/Rtc4513.cpp b/Core/Rtc4513.cpp index 61fd6dc..a7d1988 100644 --- a/Core/Rtc4513.cpp +++ b/Core/Rtc4513.cpp @@ -21,17 +21,22 @@ Rtc4513::~Rtc4513() void Rtc4513::LoadBattery() { vector rtcData = _console->GetBatteryManager()->LoadBattery(".rtc"); - - if(rtcData.size() == sizeof(_regs) + sizeof(uint64_t)) { + + if (rtcData.size() == sizeof(_regs) + sizeof(uint64_t)) + { memcpy(_regs, rtcData.data(), sizeof(_regs)); uint64_t time = 0; - for(uint32_t i = 0; i < sizeof(uint64_t); i++) { + for (uint32_t i = 0; i < sizeof(uint64_t); i++) + { time <<= 8; time |= rtcData[sizeof(_regs) + i]; } _lastTime = time; - } else { - _lastTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + else + { + _lastTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()). + count(); } } @@ -42,7 +47,8 @@ void Rtc4513::SaveBattery() memcpy(rtcData.data(), _regs, sizeof(_regs)); uint64_t time = _lastTime; - for(uint32_t i = 0; i < sizeof(uint64_t); i++) { + for (uint32_t i = 0; i < sizeof(uint64_t); i++) + { rtcData[sizeof(_regs) + i] = (time >> 56) & 0xFF; time <<= 8; } @@ -52,24 +58,28 @@ void Rtc4513::SaveBattery() void Rtc4513::UpdateTime() { - if(IsReset()) { + if (IsReset()) + { //Reset seconds to 0 _regs[0] = 0; _regs[1] = 0; } - uint64_t currentTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + uint64_t currentTime = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); uint32_t elapsedSeconds = (uint32_t)(currentTime - _lastTime); - if(elapsedSeconds <= 0) { + if (elapsedSeconds <= 0) + { return; } - if(IsStop() || IsReset() || IsHold()) { + if (IsStop() || IsReset() || IsHold()) + { _lastTime = currentTime; return; } - std::tm tm = { }; + std::tm tm = {}; tm.tm_sec = GetSeconds(); tm.tm_min = GetMinutes(); tm.tm_hour = GetHours(); @@ -78,13 +88,15 @@ void Rtc4513::UpdateTime() tm.tm_year = (GetYear() >= 90 ? 0 : 100) + GetYear(); std::time_t tt = mktime(&tm); - if(tt == -1 || GetMonth() == 0) { + if (tt == -1 || GetMonth() == 0) + { _lastTime = currentTime; return; } int8_t dowGap = 0; - if(tm.tm_wday != GetDoW()) { + if (tm.tm_wday != GetDoW()) + { //The DoW on the RTC can be set to any arbitrary value for a specific date //Check the gap between the value set by the game & the real dow for that date dowGap = (int8_t)tm.tm_wday - (int8_t)GetDoW(); @@ -121,7 +133,7 @@ void Rtc4513::UpdateTime() _regs[10] = year % 10; _regs[11] = year / 10; - + _regs[12] = (newTm.tm_wday - dowGap) % 7; _lastTime = currentTime; @@ -131,22 +143,24 @@ uint8_t Rtc4513::Read(uint16_t addr) { UpdateTime(); - switch(addr) { - case 0x4840: break; - - case 0x4841: - if(_mode == 0x0C) { - //Read mode - //LogDebug("Read: " + HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(_regs[_index])); - uint8_t index = _index; - _index = (_index + 1) & 0x0F; - return _regs[index]; - } - break; - - case 0x4842: - //Ready - return 0x80; + switch (addr) + { + case 0x4840: break; + + case 0x4841: + if (_mode == 0x0C) + { + //Read mode + //LogDebug("Read: " + HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(_regs[_index])); + uint8_t index = _index; + _index = (_index + 1) & 0x0F; + return _regs[index]; + } + break; + + case 0x4842: + //Ready + return 0x80; } return 0; @@ -156,37 +170,44 @@ void Rtc4513::Write(uint16_t addr, uint8_t value) { UpdateTime(); - switch(addr) { - case 0x4840: - _enabled = value; - if(!(_enabled & 0x01)) { - _mode = -1; - _index = -1; + switch (addr) + { + case 0x4840: + _enabled = value; + if (!(_enabled & 0x01)) + { + _mode = -1; + _index = -1; - //Turn off reset ($01) and test ($08) bits when disabled - _regs[0x0F] &= 0x06; - } - break; + //Turn off reset ($01) and test ($08) bits when disabled + _regs[0x0F] &= 0x06; + } + break; - case 0x4841: - if(_mode == -1) { - _mode = value & 0x0F; - } else if(_index == -1) { - _index = value & 0x0F; - } else if(_mode == 0x03) { - //Write mode - //LogDebug(HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(value & 0x0F)); - uint8_t index = _index; - _index = (_index + 1) & 0x0F; - _regs[index] = value & 0x0F; - } - - case 0x4842: break; + case 0x4841: + if (_mode == -1) + { + _mode = value & 0x0F; + } + else if (_index == -1) + { + _index = value & 0x0F; + } + else if (_mode == 0x03) + { + //Write mode + //LogDebug(HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(value & 0x0F)); + uint8_t index = _index; + _index = (_index + 1) & 0x0F; + _regs[index] = value & 0x0F; + } + + case 0x4842: break; } } void Rtc4513::Serialize(Serializer& s) { - ArrayInfo regs = { _regs, 0x10 }; + ArrayInfo regs = {_regs, 0x10}; s.Stream(_lastTime, _enabled, _mode, _index, regs); } diff --git a/Core/Rtc4513.h b/Core/Rtc4513.h index 1eb071c..e09e54f 100644 --- a/Core/Rtc4513.h +++ b/Core/Rtc4513.h @@ -22,12 +22,12 @@ private: uint8_t GetSeconds() { return _regs[0] + ((_regs[1] & 0x07) * 10); } uint8_t GetMinutes() { return _regs[2] + ((_regs[3] & 0x07) * 10); } uint8_t GetHours() { return _regs[4] + ((_regs[5] & 0x03) * 10); } - + uint8_t GetDay() { return _regs[6] + ((_regs[7] & 0x03) * 10); } uint8_t GetMonth() { return _regs[8] + ((_regs[9] & 0x01) * 10); } uint8_t GetYear() { return _regs[10] + (_regs[11] * 10); } uint8_t GetDoW() { return _regs[12] & 0x07; } - + void UpdateTime(); public: @@ -41,4 +41,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SPC_DSP.cpp b/Core/SPC_DSP.cpp index c0f6889..996a4b5 100644 --- a/Core/SPC_DSP.cpp +++ b/Core/SPC_DSP.cpp @@ -37,16 +37,16 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //KOF ($5C) must be initialized to $00, some games (Chester Cheetah, King of Dragons) do not initialize its value //This causes missing sound effects in both games. -static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = +static BOOST::uint8_t const initial_regs[SPC_DSP::register_count] = { - 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, - 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, - 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, - 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, - 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, - 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x00,0x4E,0x7B,0xFF, - 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, - 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF + 0x45, 0x8B, 0x5A, 0x9A, 0xE4, 0x82, 0x1B, 0x78, 0x00, 0x00, 0xAA, 0x96, 0x89, 0x0E, 0xE0, 0x80, + 0x2A, 0x49, 0x3D, 0xBA, 0x14, 0xA0, 0xAC, 0xC5, 0x00, 0x00, 0x51, 0xBB, 0x9C, 0x4E, 0x7B, 0xFF, + 0xF4, 0xFD, 0x57, 0x32, 0x37, 0xD9, 0x42, 0x22, 0x00, 0x00, 0x5B, 0x3C, 0x9F, 0x1B, 0x87, 0x9A, + 0x6F, 0x27, 0xAF, 0x7B, 0xE5, 0x68, 0x0A, 0xD9, 0x00, 0x00, 0x9A, 0xC5, 0x9C, 0x4E, 0x7B, 0xFF, + 0xEA, 0x21, 0x78, 0x4F, 0xDD, 0xED, 0x24, 0x14, 0x00, 0x00, 0x77, 0xB1, 0xD1, 0x36, 0xC1, 0x67, + 0x52, 0x57, 0x46, 0x3D, 0x59, 0xF4, 0x87, 0xA4, 0x00, 0x00, 0x7E, 0x44, 0x00, 0x4E, 0x7B, 0xFF, + 0x75, 0xF5, 0x06, 0x97, 0x10, 0xC3, 0x24, 0xBB, 0x00, 0x00, 0x7B, 0x7A, 0xE0, 0x60, 0x12, 0x0F, + 0xF7, 0x74, 0x1C, 0xE5, 0x39, 0x3D, 0x73, 0xC1, 0x00, 0x00, 0x7A, 0xB3, 0xFF, 0x4E, 0x7B, 0xFF }; // if ( io < -32768 ) io = -32768; @@ -76,19 +76,19 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = out = m.extra;\ m.out_end = &m.extra [extra_size];\ }\ -}\ +} -void SPC_DSP::set_output( sample_t* out, int size ) +void SPC_DSP::set_output(sample_t* out, int size) { - require( (size & 1) == 0 ); // must be even - if ( !out ) + require((size & 1) == 0); // must be even + if (!out) { - out = m.extra; + out = m.extra; size = extra_size; } m.out_begin = out; - m.out = out; - m.out_end = out + size; + m.out = out; + m.out_end = out + size; } // Volume registers and efb are signed! Easy to forget int8_t cast. @@ -96,40 +96,40 @@ void SPC_DSP::set_output( sample_t* out, int size ) // Gaussian interpolation -static short const gauss [512] = +static short const gauss[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, - 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, - 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, - 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, - 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, - 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, - 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, - 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, - 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, - 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, - 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, - 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, - 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, - 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, - 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, - 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, - 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, - 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, -1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, -1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, -1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, -1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, -1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, -1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, -1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, + 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, + 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, + 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, + 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, + 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, + 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305, }; inline int SPC_DSP::interpolate_cubic(voice_t const* v) @@ -145,28 +145,28 @@ inline int SPC_DSP::interpolate_cubic(voice_t const* v) float b = (v0 - v1) - a; float c = v2 - v0; float d = v1; - + float ratio = (float)(v->interp_pos & 0xFFF) / 0x1000; return (int)((d + ratio * (c + ratio * (b + ratio * a))) * 32768); } -inline int SPC_DSP::interpolate( voice_t const* v ) +inline int SPC_DSP::interpolate(voice_t const* v) { // Make pointers into gaussian based on fractional position between samples int offset = v->interp_pos >> 4 & 0xFF; short const* fwd = gauss + 255 - offset; - short const* rev = gauss + offset; // mirror left half of gaussian - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf[(v->interp_pos >> 12) + v->buf_pos]; int out; - out = (fwd [ 0] * in [0]) >> 11; - out += (fwd [256] * in [1]) >> 11; - out += (rev [256] * in [2]) >> 11; - out = (int16_t) out; - out += (rev [ 0] * in [3]) >> 11; - - CLAMP16( out ); + out = (fwd[0] * in[0]) >> 11; + out += (fwd[256] * in[1]) >> 11; + out += (rev[256] * in[2]) >> 11; + out = (int16_t)out; + out += (rev[0] * in[3]) >> 11; + + CLAMP16(out); out &= ~1; return out; } @@ -176,26 +176,26 @@ inline int SPC_DSP::interpolate( voice_t const* v ) int const simple_counter_range = 2048 * 5 * 3; // 30720 -static unsigned const counter_rates [32] = +static unsigned const counter_rates[32] = { - simple_counter_range + 1, // never fires - 2048, 1536, - 1280, 1024, 768, - 640, 512, 384, - 320, 256, 192, - 160, 128, 96, - 80, 64, 48, - 40, 32, 24, - 20, 16, 12, - 10, 8, 6, - 5, 4, 3, - 2, - 1 + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 }; -static unsigned const counter_offsets [32] = +static unsigned const counter_offsets[32] = { - 1, 0, 1040, + 1, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, @@ -205,8 +205,8 @@ static unsigned const counter_offsets [32] = 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, - 0, - 0 + 0, + 0 }; inline void SPC_DSP::init_counter() @@ -216,39 +216,39 @@ inline void SPC_DSP::init_counter() inline void SPC_DSP::run_counters() { - if ( --m.counter < 0 ) + if (--m.counter < 0) m.counter = simple_counter_range - 1; } -inline unsigned SPC_DSP::read_counter( int rate ) +inline unsigned SPC_DSP::read_counter(int rate) { - return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; + return ((unsigned)m.counter + counter_offsets[rate]) % counter_rates[rate]; } //// Envelope -inline void SPC_DSP::run_envelope( voice_t* const v ) +inline void SPC_DSP::run_envelope(voice_t* const v) { int env = v->env; - if ( v->env_mode == env_release ) // 60% + if (v->env_mode == env_release) // 60% { - if ( (env -= 0x8) < 0 ) + if ((env -= 0x8) < 0) env = 0; v->env = env; } else { int rate; - int env_data = VREG(v->regs,adsr1); - if ( m.t_adsr0 & 0x80 ) // 99% ADSR + int env_data = VREG(v->regs, adsr1); + if (m.t_adsr0 & 0x80) // 99% ADSR { - if ( v->env_mode >= env_decay ) // 99% + if (v->env_mode >= env_decay) // 99% { env--; env -= env >> 8; rate = env_data & 0x1F; - if ( v->env_mode == env_decay ) // 1% + if (v->env_mode == env_decay) // 1% rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; } else // env_attack @@ -260,9 +260,9 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else // GAIN { int mode; - env_data = VREG(v->regs,gain); + env_data = VREG(v->regs, gain); mode = env_data >> 5; - if ( mode < 4 ) // direct + if (mode < 4) // direct { env = env_data * 0x10; rate = 31; @@ -270,11 +270,11 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else { rate = env_data & 0x1F; - if ( mode == 4 ) // 4: linear decrease + if (mode == 4) // 4: linear decrease { env -= 0x20; } - else if ( mode < 6 ) // 5: exponential decrease + else if (mode < 6) // 5: exponential decrease { env--; env -= env >> 8; @@ -282,27 +282,27 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else // 6,7: linear increase { env += 0x20; - if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + if (mode > 6 && (unsigned)v->hidden_env >= 0x600) env += 0x8 - 0x20; // 7: two-slope linear increase } } } - + // Sustain level - if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + if ((env >> 8) == (env_data >> 5) && v->env_mode == env_decay) v->env_mode = env_sustain; - + v->hidden_env = env; - + // unsigned cast because linear decrease going negative also triggers this - if ( (unsigned) env > 0x7FF ) + if ((unsigned)env > 0x7FF) { env = (env < 0 ? 0 : 0x7FF); - if ( v->env_mode == env_attack ) + if (v->env_mode == env_attack) v->env_mode = env_decay; } - - if ( !read_counter( rate ) ) + + if (!read_counter(rate)) v->env = env; // nothing else is controlled by the counter } } @@ -310,40 +310,40 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) //// BRR Decoding -inline void SPC_DSP::decode_brr( voice_t* v ) +inline void SPC_DSP::decode_brr(voice_t* v) { // Arrange the four input nybbles in 0xABCD order for easy decoding int nybbles = m.t_brr_byte * 0x100 + readRam(v->brr_addr + v->brr_offset + 1); - + int const header = m.t_brr_header; - + // Write to next four samples in circular buffer - int* pos = &v->buf [v->buf_pos]; + int* pos = &v->buf[v->buf_pos]; int* end; - if ( (v->buf_pos += 4) >= brr_buf_size ) + if ((v->buf_pos += 4) >= brr_buf_size) v->buf_pos = 0; - + // Decode four samples - for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) + for (end = pos + 4; pos < end; pos++, nybbles <<= 4) { // Extract nybble and sign-extend - int s = (int16_t) nybbles >> 12; - + int s = (int16_t)nybbles >> 12; + // Shift sample based on header int const shift = header >> 4; s = (s << shift) >> 1; - if ( shift >= 0xD ) // handle invalid range + if (shift >= 0xD) // handle invalid range s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) - + // Apply IIR filter (8 is the most commonly used) int const filter = header & 0x0C; - int const p1 = pos [brr_buf_size - 1]; - int const p2 = pos [brr_buf_size - 2] >> 1; - if ( filter >= 8 ) + int const p1 = pos[brr_buf_size - 1]; + int const p2 = pos[brr_buf_size - 2] >> 1; + if (filter >= 8) { s += p1; s -= p2; - if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + if (filter == 8) // s += p1 * 0.953125 - p2 * 0.46875 { s += p2 >> 4; s += (p1 * -3) >> 6; @@ -354,16 +354,16 @@ inline void SPC_DSP::decode_brr( voice_t* v ) s += (p2 * 3) >> 4; } } - else if ( filter ) // s += p1 * 0.46875 + else if (filter) // s += p1 * 0.46875 { s += p1 >> 1; s += (-p1) >> 5; } - + // Adjust and write sample - CLAMP16( s ); - s = (int16_t) (s * 2); - pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + CLAMP16(s); + s = (int16_t)(s * 2); + pos[brr_buf_size] = pos[0] = s; // second copy simplifies wrap-around } } @@ -372,33 +372,36 @@ inline void SPC_DSP::decode_brr( voice_t* v ) #define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() -MISC_CLOCK( 27 ) +MISC_CLOCK(27) { m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON } -MISC_CLOCK( 28 ) + +MISC_CLOCK(28) { m.t_non = REG(non); m.t_eon = REG(eon); m.t_dir = REG(dir); } -MISC_CLOCK( 29 ) + +MISC_CLOCK(29) { - if ( (m.every_other_sample ^= 1) != 0 ) + if ((m.every_other_sample ^= 1) != 0) m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read } -MISC_CLOCK( 30 ) + +MISC_CLOCK(30) { - if ( m.every_other_sample ) + if (m.every_other_sample) { - m.kon = m.new_kon; - m.t_koff = REG(koff) | m.mute_mask; + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; } - + run_counters(); - + // Noise - if ( !read_counter( REG(flg) & 0x1F ) ) + if (!read_counter(REG(flg) & 0x1F)) { int feedback = (m.noise << 13) ^ (m.noise << 14); m.noise = (feedback & 0x4000) ^ (m.noise >> 1); @@ -410,133 +413,139 @@ MISC_CLOCK( 30 ) #define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) -inline VOICE_CLOCK( V1 ) +inline VOICE_CLOCK(V1) { m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; - m.t_srcn = VREG(v->regs,srcn); + m.t_srcn = VREG(v->regs, srcn); } -inline VOICE_CLOCK( V2 ) + +inline VOICE_CLOCK(V2) { // Read sample pointer (ignored if not needed) uint16_t entry = m.t_dir_addr; - if ( !v->kon_delay ) + if (!v->kon_delay) entry += 2; - m.t_brr_next_addr = readRam(entry) | (readRam(entry+1) << 8); - - m.t_adsr0 = VREG(v->regs,adsr0); - + m.t_brr_next_addr = readRam(entry) | (readRam(entry + 1) << 8); + + m.t_adsr0 = VREG(v->regs, adsr0); + // Read pitch, spread over two clocks - m.t_pitch = VREG(v->regs,pitchl); + m.t_pitch = VREG(v->regs, pitchl); } -inline VOICE_CLOCK( V3a ) + +inline VOICE_CLOCK(V3a) { - m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; + m.t_pitch += (VREG(v->regs, pitchh) & 0x3F) << 8; } -inline VOICE_CLOCK( V3b ) + +inline VOICE_CLOCK(V3b) { // Read BRR header and byte - m.t_brr_byte = readRam(v->brr_addr + v->brr_offset); + m.t_brr_byte = readRam(v->brr_addr + v->brr_offset); m.t_brr_header = readRam(v->brr_addr); // brr_addr doesn't need masking } -VOICE_CLOCK( V3c ) + +VOICE_CLOCK(V3c) { // Pitch modulation using previous voice's output - if ( m.t_pmon & v->vbit ) + if (m.t_pmon & v->vbit) m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; - - if ( v->kon_delay ) + + if (v->kon_delay) { // Get ready to start BRR decoding on next sample - if ( v->kon_delay == 5 ) + if (v->kon_delay == 5) { - v->brr_addr = m.t_brr_next_addr; - v->brr_offset = 1; - v->buf_pos = 0; + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; m.t_brr_header = 0; // header is ignored on this sample - m.kon_check = true; + m.kon_check = true; } - + // Envelope is never run during KON - v->env = 0; + v->env = 0; v->hidden_env = 0; - + // Disable BRR decoding until last three samples v->interp_pos = 0; - if ( --v->kon_delay & 3 ) + if (--v->kon_delay & 3) v->interp_pos = 0x4000; - + // Pitch is never added during KON m.t_pitch = 0; } - + // Gaussian interpolation { - int output = _settings->GetAudioConfig().EnableCubicInterpolation ? interpolate_cubic(v) : interpolate( v ); - + int output = _settings->GetAudioConfig().EnableCubicInterpolation ? interpolate_cubic(v) : interpolate(v); + // Noise - if ( m.t_non & v->vbit ) - output = (int16_t) (m.noise * 2); - + if (m.t_non & v->vbit) + output = (int16_t)(m.noise * 2); + // Apply envelope m.t_output = (output * v->env) >> 11 & ~1; - v->t_envx_out = (uint8_t) (v->env >> 4); + v->t_envx_out = (uint8_t)(v->env >> 4); } - + // Immediate silence due to end of sample or soft reset - if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + if (REG(flg) & 0x80 || (m.t_brr_header & 3) == 1) { v->env_mode = env_release; - v->env = 0; + v->env = 0; } - - if ( m.every_other_sample ) + + if (m.every_other_sample) { // KOFF - if ( m.t_koff & v->vbit ) + if (m.t_koff & v->vbit) v->env_mode = env_release; - + // KON - if ( m.kon & v->vbit ) + if (m.kon & v->vbit) { v->kon_delay = 5; - v->env_mode = env_attack; + v->env_mode = env_attack; } } - + // Run envelope for next sample - if ( !v->kon_delay ) - run_envelope( v ); + if (!v->kon_delay) + run_envelope(v); } -inline void SPC_DSP::voice_output( voice_t const* v, int ch ) + +inline void SPC_DSP::voice_output(voice_t const* v, int ch) { // Apply left/right volume - int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; - + int amp = (m.t_output * (int8_t)VREG(v->regs, voll + ch)) >> 7; + // Add to output total - m.t_main_out [ch] += amp; - CLAMP16( m.t_main_out [ch] ); - + m.t_main_out[ch] += amp; + CLAMP16(m.t_main_out [ch]); + // Optionally add to echo total - if ( m.t_eon & v->vbit ) + if (m.t_eon & v->vbit) { - m.t_echo_out [ch] += amp; - CLAMP16( m.t_echo_out [ch] ); + m.t_echo_out[ch] += amp; + CLAMP16(m.t_echo_out [ch]); } } -VOICE_CLOCK( V4 ) + +VOICE_CLOCK(V4) { // Decode BRR m.t_looped = 0; - if ( v->interp_pos >= 0x4000 ) + if (v->interp_pos >= 0x4000) { - decode_brr( v ); - - if ( (v->brr_offset += 2) >= brr_block_size ) + decode_brr(v); + + if ((v->brr_offset += 2) >= brr_block_size) { // Start decoding next BRR block - assert( v->brr_offset == brr_block_size ); + assert(v->brr_offset == brr_block_size); v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; - if ( m.t_brr_header & 1 ) + if (m.t_brr_header & 1) { v->brr_addr = m.t_brr_next_addr; m.t_looped = v->vbit; @@ -544,66 +553,88 @@ VOICE_CLOCK( V4 ) v->brr_offset = 1; } } - + // Apply pitch v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; - + // Keep from getting too far ahead (when using pitch modulation) - if ( v->interp_pos > 0x7FFF ) + if (v->interp_pos > 0x7FFF) v->interp_pos = 0x7FFF; - + // Output left - voice_output( v, 0 ); + voice_output(v, 0); } -inline VOICE_CLOCK( V5 ) + +inline VOICE_CLOCK(V5) { // Output right - voice_output( v, 1 ); - + voice_output(v, 1); + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier int endx_buf = REG(endx) | m.t_looped; - + // Clear bit in ENDX if KON just began - if ( v->kon_delay == 5 ) + if (v->kon_delay == 5) endx_buf &= ~v->vbit; - m.endx_buf = (uint8_t) endx_buf; + m.endx_buf = (uint8_t)endx_buf; } -inline VOICE_CLOCK( V6 ) + +inline VOICE_CLOCK(V6) { - (void) v; // avoid compiler warning about unused v - m.outx_buf = (uint8_t) (m.t_output >> 8); + (void)v; // avoid compiler warning about unused v + m.outx_buf = (uint8_t)(m.t_output >> 8); } -inline VOICE_CLOCK( V7 ) + +inline VOICE_CLOCK(V7) { // Update ENDX REG(endx) = m.endx_buf; - + m.envx_buf = v->t_envx_out; } -inline VOICE_CLOCK( V8 ) + +inline VOICE_CLOCK(V8) { // Update OUTX - VREG(v->regs,outx) = m.outx_buf; + VREG(v->regs, outx) = m.outx_buf; } -inline VOICE_CLOCK( V9 ) + +inline VOICE_CLOCK(V9) { // Update ENVX - VREG(v->regs,envx) = m.envx_buf; + VREG(v->regs, envx) = m.envx_buf; } // Most voices do all these in one clock, so make a handy composite -inline VOICE_CLOCK( V3 ) +inline VOICE_CLOCK(V3) { - voice_V3a( v ); - voice_V3b( v ); - voice_V3c( v ); + voice_V3a(v); + voice_V3b(v); + voice_V3c(v); } // Common combinations of voice steps on different voices. This greatly reduces // code size and allows everything to be inlined in these functions. -VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } -VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } -VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } +VOICE_CLOCK(V7_V4_V1) +{ + voice_V7(v); + voice_V1(v + 3); + voice_V4(v + 1); +} + +VOICE_CLOCK(V8_V5_V2) +{ + voice_V8(v); + voice_V5(v + 1); + voice_V2(v + 2); +} + +VOICE_CLOCK(V9_V6_V3) +{ + voice_V9(v); + voice_V6(v + 1); + voice_V3(v + 2); +} //// Echo @@ -619,146 +650,157 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } #define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() -inline void SPC_DSP::echo_read( int ch ) +inline void SPC_DSP::echo_read(int ch) { uint16_t echoPtr = ECHO_PTR(ch); - int16_t s = readRam(echoPtr) | (readRam(echoPtr+1) << 8); + int16_t s = readRam(echoPtr) | (readRam(echoPtr + 1) << 8); // second copy simplifies wrap-around handling - ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; + ECHO_FIR(0)[ch] = ECHO_FIR(8)[ch] = s >> 1; } -ECHO_CLOCK( 22 ) +ECHO_CLOCK(22) { // History - if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) + if (++m.echo_hist_pos >= &m.echo_hist[echo_hist_size]) m.echo_hist_pos = m.echo_hist; - + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; - echo_read( 0 ); - + echo_read(0); + // FIR (using l and r temporaries below helps compiler optimize) - int l = CALC_FIR( 0, 0 ); - int r = CALC_FIR( 0, 1 ); - - m.t_echo_in [0] = l; - m.t_echo_in [1] = r; + int l = CALC_FIR(0, 0); + int r = CALC_FIR(0, 1); + + m.t_echo_in[0] = l; + m.t_echo_in[1] = r; } -ECHO_CLOCK( 23 ) + +ECHO_CLOCK(23) { - int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); - int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; - - echo_read( 1 ); + int l = CALC_FIR(1, 0) + CALC_FIR(2, 0); + int r = CALC_FIR(1, 1) + CALC_FIR(2, 1); + + m.t_echo_in[0] += l; + m.t_echo_in[1] += r; + + echo_read(1); } -ECHO_CLOCK( 24 ) + +ECHO_CLOCK(24) { - int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); - int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; + int l = CALC_FIR(3, 0) + CALC_FIR(4, 0) + CALC_FIR(5, 0); + int r = CALC_FIR(3, 1) + CALC_FIR(4, 1) + CALC_FIR(5, 1); + + m.t_echo_in[0] += l; + m.t_echo_in[1] += r; } -ECHO_CLOCK( 25 ) + +ECHO_CLOCK(25) { - int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); - int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); - - l = (int16_t) l; - r = (int16_t) r; - - l += (int16_t) CALC_FIR( 7, 0 ); - r += (int16_t) CALC_FIR( 7, 1 ); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_in [0] = l & ~1; - m.t_echo_in [1] = r & ~1; + int l = m.t_echo_in[0] + CALC_FIR(6, 0); + int r = m.t_echo_in[1] + CALC_FIR(6, 1); + + l = (int16_t)l; + r = (int16_t)r; + + l += (int16_t)CALC_FIR(7, 0); + r += (int16_t)CALC_FIR(7, 1); + + CLAMP16(l); + CLAMP16(r); + + m.t_echo_in[0] = l & ~1; + m.t_echo_in[1] = r & ~1; } -inline int SPC_DSP::echo_output( int ch ) + +inline int SPC_DSP::echo_output(int ch) { - int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + - (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); - CLAMP16( out ); + int out = (int16_t)((m.t_main_out[ch] * (int8_t)REG(mvoll + ch * 0x10)) >> 7) + + (int16_t)((m.t_echo_in[ch] * (int8_t)REG(evoll + ch * 0x10)) >> 7); + CLAMP16(out); return out; } -ECHO_CLOCK( 26 ) + +ECHO_CLOCK(26) { // Left output volumes // (save sample for next clock so we can output both together) - m.t_main_out [0] = echo_output( 0 ); - + m.t_main_out[0] = echo_output(0); + // Echo feedback - int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); - int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_out [0] = l & ~1; - m.t_echo_out [1] = r & ~1; + int l = m.t_echo_out[0] + (int16_t)((m.t_echo_in[0] * (int8_t)REG(efb)) >> 7); + int r = m.t_echo_out[1] + (int16_t)((m.t_echo_in[1] * (int8_t)REG(efb)) >> 7); + + CLAMP16(l); + CLAMP16(r); + + m.t_echo_out[0] = l & ~1; + m.t_echo_out[1] = r & ~1; } -ECHO_CLOCK( 27 ) + +ECHO_CLOCK(27) { // Output - int l = m.t_main_out [0]; - int r = echo_output( 1 ); - m.t_main_out [0] = 0; - m.t_main_out [1] = 0; - + int l = m.t_main_out[0]; + int r = echo_output(1); + m.t_main_out[0] = 0; + m.t_main_out[1] = 0; + // TODO: global muting isn't this simple (turns DAC on and off // or something, causing small ~37-sample pulse when first muted) - if ( REG(flg) & 0x40 ) + if (REG(flg) & 0x40) { l = 0; r = 0; } - + // Output sample to DAC - #ifdef SPC_DSP_OUT_HOOK +#ifdef SPC_DSP_OUT_HOOK SPC_DSP_OUT_HOOK( l, r ); - #else - sample_t* out = m.out; - WRITE_SAMPLES( l, r, out ); - m.out = out; - #endif +#else + sample_t* out = m.out; + WRITE_SAMPLES(l, r, out); + m.out = out; +#endif } -ECHO_CLOCK( 28 ) + +ECHO_CLOCK(28) { m.t_echo_enabled = REG(flg); } -inline void SPC_DSP::echo_write( int ch ) + +inline void SPC_DSP::echo_write(int ch) { - if(!(m.t_echo_enabled & 0x20)) { + if (!(m.t_echo_enabled & 0x20)) + { uint16_t echoPtr = ECHO_PTR(ch); writeRam(echoPtr, m.t_echo_out[ch]); - writeRam(echoPtr+1, m.t_echo_out[ch] >> 8); + writeRam(echoPtr + 1, m.t_echo_out[ch] >> 8); } - m.t_echo_out [ch] = 0; + m.t_echo_out[ch] = 0; } -ECHO_CLOCK( 29 ) + +ECHO_CLOCK(29) { m.t_esa = REG(esa); - - if ( !m.echo_offset ) + + if (!m.echo_offset) m.echo_length = (REG(edl) & 0x0F) * 0x800; - + m.echo_offset += 4; - if ( m.echo_offset >= m.echo_length ) + if (m.echo_offset >= m.echo_length) m.echo_offset = 0; - + // Write left echo - echo_write( 0 ); - + echo_write(0); + m.t_echo_enabled = REG(flg); } -ECHO_CLOCK( 30 ) + +ECHO_CLOCK(30) { // Write right echo - echo_write( 1 ); + echo_write(1); } @@ -808,8 +850,7 @@ PHASE(27) misc_27(); echo_27();\ PHASE(28) misc_28(); echo_28();\ PHASE(29) misc_29(); echo_29();\ PHASE(30) misc_30();V(V3c,0) echo_30();\ -PHASE(31) V(V4,0) V(V1,2)\ - +PHASE(31) V(V4,0) V(V1,2) #if !SPC_DSP_CUSTOM_RUN void SPC_DSP::run() @@ -818,9 +859,9 @@ void SPC_DSP::run() m.phase = (phase + 1) & 31; switch (phase) { - #define PHASE( n ) if ( n ) break; case n: +#define PHASE( n ) if ( n ) break; case n: GEN_DSP_TIMING - #undef PHASE +#undef PHASE } } @@ -832,42 +873,46 @@ inline void SPC_DSP::writeRam(uint16_t addr, uint8_t value) { _spc->DspWriteRam( //// Setup -void SPC_DSP::init( Spc *spc, EmuSettings *settings, void* ram_64k ) +void SPC_DSP::init(Spc* spc, EmuSettings* settings, void* ram_64k) { _spc = spc; _settings = settings; - m.ram = (uint8_t*) ram_64k; - mute_voices( 0 ); - disable_surround( false ); - set_output( 0, 0 ); + m.ram = (uint8_t*)ram_64k; + mute_voices(0); + disable_surround(false); + set_output(0, 0); reset(); - - #ifndef NDEBUG - // be sure this sign-extends - assert( (int16_t) 0x8000 == -0x8000 ); - - // be sure right shift preserves sign - assert( (-1 >> 1) == -1 ); - - // check clamp macro - int i; - i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); - i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); - - blargg_verify_byte_order(); - #endif + +#ifndef NDEBUG + // be sure this sign-extends + assert((int16_t) 0x8000 == -0x8000); + + // be sure right shift preserves sign + assert((-1 >> 1) == -1); + + // check clamp macro + int i; + i = +0x8000; + CLAMP16(i); + assert(i == +0x7FFF); + i = -0x8001; + CLAMP16(i); + assert(i == -0x8000); + + blargg_verify_byte_order(); +#endif } void SPC_DSP::soft_reset_common() { - require( m.ram ); // init() must have been called already - - m.noise = 0x4000; - m.echo_hist_pos = m.echo_hist; + require(m.ram); // init() must have been called already + + m.noise = 0x4000; + m.echo_hist_pos = m.echo_hist; m.every_other_sample = 1; - m.echo_offset = 0; - m.phase = 0; - + m.echo_offset = 0; + m.phase = 0; + init_counter(); } @@ -877,61 +922,61 @@ void SPC_DSP::soft_reset() soft_reset_common(); } -void SPC_DSP::load( uint8_t const regs [register_count] ) +void SPC_DSP::load(uint8_t const regs[register_count]) { - memcpy( m.regs, regs, sizeof m.regs ); - memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - + memcpy(m.regs, regs, sizeof m.regs); + memset(&m.regs[register_count], 0, offsetof(state_t, ram) - register_count); + // Internal state - for ( int i = voice_count; --i >= 0; ) + for (int i = voice_count; --i >= 0;) { - voice_t* v = &m.voices [i]; + voice_t* v = &m.voices[i]; v->brr_offset = 1; - v->vbit = 1 << i; - v->regs = &m.regs [i * 0x10]; + v->vbit = 1 << i; + v->regs = &m.regs[i * 0x10]; } m.new_kon = REG(kon); - m.t_dir = REG(dir); - m.t_esa = REG(esa); - + m.t_dir = REG(dir); + m.t_esa = REG(esa); + soft_reset_common(); } -void SPC_DSP::reset() { load( initial_regs ); } +void SPC_DSP::reset() { load(initial_regs); } //// State save/load #if !SPC_NO_COPY_STATE_FUNCS -void SPC_State_Copier::copy( void* state, size_t size ) +void SPC_State_Copier::copy(void* state, size_t size) { - func( buf, state, size ); + func(buf, state, size); } -int SPC_State_Copier::copy_int( int state, int size ) +int SPC_State_Copier::copy_int(int state, int size) { - BOOST::uint8_t s [2]; - SET_LE16( s, state ); - func( buf, &s, size ); - return GET_LE16( s ); + BOOST::uint8_t s[2]; + SET_LE16(s, state); + func(buf, &s, size); + return GET_LE16(s); } -void SPC_State_Copier::skip( int count ) +void SPC_State_Copier::skip(int count) { - if ( count > 0 ) + if (count > 0) { - char temp [64]; - memset( temp, 0, sizeof temp ); + char temp[64]; + memset(temp, 0, sizeof temp); do { int n = sizeof temp; - if ( n > count ) + if (n > count) n = count; count -= n; - func( buf, temp, n ); + func(buf, temp, n); } - while ( count ); + while (count); } } @@ -939,107 +984,107 @@ void SPC_State_Copier::extra() { int n = 0; SPC_State_Copier& copier = *this; - SPC_COPY( uint8_t, n ); - skip( n ); + SPC_COPY(uint8_t, n); + skip(n); } -void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) +void SPC_DSP::copy_state(unsigned char** io, copy_func_t copy) { - SPC_State_Copier copier( io, copy ); - + SPC_State_Copier copier(io, copy); + // DSP registers - copier.copy( m.regs, register_count ); - + copier.copy(m.regs, register_count); + // Internal state - + // Voices int i; - for ( i = 0; i < voice_count; i++ ) + for (i = 0; i < voice_count; i++) { - voice_t* v = &m.voices [i]; - + voice_t* v = &m.voices[i]; + // BRR buffer int i; - for ( i = 0; i < brr_buf_size; i++ ) + for (i = 0; i < brr_buf_size; i++) { - int s = v->buf [i]; - SPC_COPY( int16_t, s ); - v->buf [i] = v->buf [i + brr_buf_size] = s; + int s = v->buf[i]; + SPC_COPY(int16_t, s); + v->buf[i] = v->buf[i + brr_buf_size] = s; } - - SPC_COPY( uint16_t, v->interp_pos ); - SPC_COPY( uint16_t, v->brr_addr ); - SPC_COPY( uint16_t, v->env ); - SPC_COPY( int16_t, v->hidden_env ); - SPC_COPY( uint8_t, v->buf_pos ); - SPC_COPY( uint8_t, v->brr_offset ); - SPC_COPY( uint8_t, v->kon_delay ); + + SPC_COPY(uint16_t, v->interp_pos); + SPC_COPY(uint16_t, v->brr_addr); + SPC_COPY(uint16_t, v->env); + SPC_COPY(int16_t, v->hidden_env); + SPC_COPY(uint8_t, v->buf_pos); + SPC_COPY(uint8_t, v->brr_offset); + SPC_COPY(uint8_t, v->kon_delay); { int m = v->env_mode; - SPC_COPY( uint8_t, m ); - v->env_mode = (enum env_mode_t) m; + SPC_COPY(uint8_t, m); + v->env_mode = (enum env_mode_t)m; } - SPC_COPY( uint8_t, v->t_envx_out ); - + SPC_COPY(uint8_t, v->t_envx_out); + copier.extra(); } - + // Echo history - for ( i = 0; i < echo_hist_size; i++ ) + for (i = 0; i < echo_hist_size; i++) { int j; - for ( j = 0; j < 2; j++ ) + for (j = 0; j < 2; j++) { - int s = m.echo_hist_pos [i] [j]; - SPC_COPY( int16_t, s ); - m.echo_hist [i] [j] = s; // write back at offset 0 + int s = m.echo_hist_pos[i][j]; + SPC_COPY(int16_t, s); + m.echo_hist[i][j] = s; // write back at offset 0 } } m.echo_hist_pos = m.echo_hist; - memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); - + memcpy(&m.echo_hist[echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist[0]); + // Misc - SPC_COPY( uint8_t, m.every_other_sample ); - SPC_COPY( uint8_t, m.kon ); - - SPC_COPY( uint16_t, m.noise ); - SPC_COPY( uint16_t, m.counter ); - SPC_COPY( uint16_t, m.echo_offset ); - SPC_COPY( uint16_t, m.echo_length ); - SPC_COPY( uint8_t, m.phase ); - - SPC_COPY( uint8_t, m.new_kon ); - SPC_COPY( uint8_t, m.endx_buf ); - SPC_COPY( uint8_t, m.envx_buf ); - SPC_COPY( uint8_t, m.outx_buf ); - - SPC_COPY( uint8_t, m.t_pmon ); - SPC_COPY( uint8_t, m.t_non ); - SPC_COPY( uint8_t, m.t_eon ); - SPC_COPY( uint8_t, m.t_dir ); - SPC_COPY( uint8_t, m.t_koff ); - - SPC_COPY( uint16_t, m.t_brr_next_addr ); - SPC_COPY( uint8_t, m.t_adsr0 ); - SPC_COPY( uint8_t, m.t_brr_header ); - SPC_COPY( uint8_t, m.t_brr_byte ); - SPC_COPY( uint8_t, m.t_srcn ); - SPC_COPY( uint8_t, m.t_esa ); - SPC_COPY( uint8_t, m.t_echo_enabled ); - - SPC_COPY( int16_t, m.t_main_out [0] ); - SPC_COPY( int16_t, m.t_main_out [1] ); - SPC_COPY( int16_t, m.t_echo_out [0] ); - SPC_COPY( int16_t, m.t_echo_out [1] ); - SPC_COPY( int16_t, m.t_echo_in [0] ); - SPC_COPY( int16_t, m.t_echo_in [1] ); - - SPC_COPY( uint16_t, m.t_dir_addr ); - SPC_COPY( uint16_t, m.t_pitch ); - SPC_COPY( int16_t, m.t_output ); - SPC_COPY( uint16_t, m.t_echo_ptr ); - SPC_COPY( uint8_t, m.t_looped ); - + SPC_COPY(uint8_t, m.every_other_sample); + SPC_COPY(uint8_t, m.kon); + + SPC_COPY(uint16_t, m.noise); + SPC_COPY(uint16_t, m.counter); + SPC_COPY(uint16_t, m.echo_offset); + SPC_COPY(uint16_t, m.echo_length); + SPC_COPY(uint8_t, m.phase); + + SPC_COPY(uint8_t, m.new_kon); + SPC_COPY(uint8_t, m.endx_buf); + SPC_COPY(uint8_t, m.envx_buf); + SPC_COPY(uint8_t, m.outx_buf); + + SPC_COPY(uint8_t, m.t_pmon); + SPC_COPY(uint8_t, m.t_non); + SPC_COPY(uint8_t, m.t_eon); + SPC_COPY(uint8_t, m.t_dir); + SPC_COPY(uint8_t, m.t_koff); + + SPC_COPY(uint16_t, m.t_brr_next_addr); + SPC_COPY(uint8_t, m.t_adsr0); + SPC_COPY(uint8_t, m.t_brr_header); + SPC_COPY(uint8_t, m.t_brr_byte); + SPC_COPY(uint8_t, m.t_srcn); + SPC_COPY(uint8_t, m.t_esa); + SPC_COPY(uint8_t, m.t_echo_enabled); + + SPC_COPY(int16_t, m.t_main_out [0]); + SPC_COPY(int16_t, m.t_main_out [1]); + SPC_COPY(int16_t, m.t_echo_out [0]); + SPC_COPY(int16_t, m.t_echo_out [1]); + SPC_COPY(int16_t, m.t_echo_in [0]); + SPC_COPY(int16_t, m.t_echo_in [1]); + + SPC_COPY(uint16_t, m.t_dir_addr); + SPC_COPY(uint16_t, m.t_pitch); + SPC_COPY(int16_t, m.t_output); + SPC_COPY(uint16_t, m.t_echo_ptr); + SPC_COPY(uint8_t, m.t_looped); + copier.extra(); } #endif diff --git a/Core/SPC_DSP.h b/Core/SPC_DSP.h index 8d80220..8641524 100644 --- a/Core/SPC_DSP.h +++ b/Core/SPC_DSP.h @@ -5,160 +5,188 @@ #define SPC_DSP_H #include "blargg_common.h" -extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } + +extern "C" { +typedef void (*dsp_copy_func_t)(unsigned char** io, void* state, size_t); +} class Spc; class EmuSettings; -class SPC_DSP { + +class SPC_DSP +{ public: typedef BOOST::uint8_t uint8_t; - -// Setup + + // Setup // Initializes DSP and has it use the 64K RAM provided - void init( Spc* spc, EmuSettings* settings, void* ram_64k ); + void init(Spc* spc, EmuSettings* settings, void* ram_64k); // Sets destination for output samples. If out is NULL or out_size is 0, // doesn't generate any. typedef short sample_t; - void set_output( sample_t* out, int out_size ); + void set_output(sample_t* out, int out_size); // Number of samples written to output since it was last set, always // a multiple of 2. Undefined if more samples were generated than // output buffer could hold. int sample_count() const; -// Emulation + // Emulation // Resets DSP to power-on state void reset(); // Emulates pressing reset switch on SNES void soft_reset(); - + // Reads/writes DSP registers. For accuracy, you must first call run() // to catch the DSP up to present. - int read ( int addr ) const; - void write( int addr, int data ); + int read(int addr) const; + void write(int addr, int data); // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks // a pair of samples is be generated. void run(); - + bool isMuted() { return (m.regs[r_flg] & 0x40) != 0; } void copyRegs(uint8_t* output) { memcpy(output, m.regs, register_count); } uint8_t readRam(uint16_t addr); void writeRam(uint16_t addr, uint8_t value); -// Sound control + // Sound control // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). // Reduces emulation accuracy. enum { voice_count = 8 }; - void mute_voices( int mask ); -// State - + void mute_voices(int mask); + + // State + // Resets DSP and uses supplied values to initialize registers enum { register_count = 128 }; - void load( uint8_t const regs [register_count] ); + + void load(uint8_t const regs[register_count]); // Saves/loads exact emulator state enum { state_size = 640 }; // maximum space needed when saving typedef dsp_copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); + void copy_state(unsigned char** io, copy_func_t); // Returns non-zero if new key-on events occurred since last call bool check_kon(); - -// DSP register addresses + + // DSP register addresses // Global registers - enum { - r_mvoll = 0x0C, r_mvolr = 0x1C, - r_evoll = 0x2C, r_evolr = 0x3C, - r_kon = 0x4C, r_koff = 0x5C, - r_flg = 0x6C, r_endx = 0x7C, - r_efb = 0x0D, r_pmon = 0x2D, - r_non = 0x3D, r_eon = 0x4D, - r_dir = 0x5D, r_esa = 0x6D, - r_edl = 0x7D, - r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + enum + { + r_mvoll = 0x0C, + r_mvolr = 0x1C, + r_evoll = 0x2C, + r_evolr = 0x3C, + r_kon = 0x4C, + r_koff = 0x5C, + r_flg = 0x6C, + r_endx = 0x7C, + r_efb = 0x0D, + r_pmon = 0x2D, + r_non = 0x3D, + r_eon = 0x4D, + r_dir = 0x5D, + r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F }; // Voice registers - enum { - v_voll = 0x00, v_volr = 0x01, - v_pitchl = 0x02, v_pitchh = 0x03, - v_srcn = 0x04, v_adsr0 = 0x05, - v_adsr1 = 0x06, v_gain = 0x07, - v_envx = 0x08, v_outx = 0x09 + enum + { + v_voll = 0x00, + v_volr = 0x01, + v_pitchl = 0x02, + v_pitchh = 0x03, + v_srcn = 0x04, + v_adsr0 = 0x05, + v_adsr1 = 0x06, + v_gain = 0x07, + v_envx = 0x08, + v_outx = 0x09 }; public: enum { extra_size = 16 }; - sample_t* extra() { return m.extra; } + + sample_t* extra() { return m.extra; } sample_t const* out_pos() const { return m.out; } - void disable_surround( bool ) { } // not supported + + void disable_surround(bool) + { + } // not supported public: BLARGG_DISABLE_NOTHROW - - typedef BOOST::int8_t int8_t; + + typedef BOOST::int8_t int8_t; typedef BOOST::int16_t int16_t; - + enum { echo_hist_size = 8 }; - + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t { - int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) - int buf_pos; // place in buffer where next samples will be decoded - int interp_pos; // relative fractional position in sample (0x1000 = 1.0) - int brr_addr; // address of current BRR block - int brr_offset; // current decoding offset in BRR block - uint8_t* regs; // pointer to voice's DSP registers - int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. - int kon_delay; // KON delay/current setup phase + int buf[brr_buf_size * 2]; // decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase env_mode_t env_mode; - int env; // current envelope level - int hidden_env; // used by GAIN mode 7, very obscure quirk + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk uint8_t t_envx_out; }; + private: enum { brr_block_size = 9 }; - + struct state_t { - uint8_t regs [register_count]; - + uint8_t regs[register_count]; + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) - int echo_hist [echo_hist_size * 2] [2]; - int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - + int echo_hist[echo_hist_size * 2][2]; + int (*echo_hist_pos)[2]; // &echo_hist [0 to 7] + int every_other_sample; // toggles every sample - int kon; // KON value when last checked + int kon; // KON value when last checked int noise; int counter; - int echo_offset; // offset from ESA in echo buffer - int echo_length; // number of bytes that echo_offset will stop at - int phase; // next clock cycle to run (0-31) - bool kon_check; // set when a new KON occurs - + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + int phase; // next clock cycle to run (0-31) + bool kon_check; // set when a new KON occurs + // Hidden registers also written to when main register is written to int new_kon; uint8_t endx_buf; uint8_t envx_buf; uint8_t outx_buf; - + // Temporary state between clocks - + // read once per sample int t_pmon; int t_non; int t_eon; int t_dir; int t_koff; - + // read a few clocks ahead then used int t_brr_next_addr; int t_adsr0; @@ -167,67 +195,68 @@ private: int t_srcn; int t_esa; int t_echo_enabled; - + // internal state that is recalculated every sample uint16_t t_dir_addr; int t_pitch; int t_output; int t_looped; int t_echo_ptr; - + // left/right sums - int t_main_out [2]; - int t_echo_out [2]; - int t_echo_in [2]; - - voice_t voices [voice_count]; - + int t_main_out[2]; + int t_echo_out[2]; + int t_echo_in[2]; + + voice_t voices[voice_count]; + // non-emulation state uint8_t* ram; // 64K shared RAM between DSP and SMP int mute_mask; sample_t* out; sample_t* out_end; sample_t* out_begin; - sample_t extra [extra_size]; + sample_t extra[extra_size]; }; + state_t m; Spc* _spc; EmuSettings* _settings; - + void init_counter(); void run_counters(); - unsigned read_counter( int rate ); - + unsigned read_counter(int rate); + int interpolate_cubic(voice_t const* v); - int interpolate( voice_t const* v ); - void run_envelope( voice_t* const v ); - void decode_brr( voice_t* v ); + int interpolate(voice_t const* v); + void run_envelope(voice_t* const v); + void decode_brr(voice_t* v); void misc_27(); void misc_28(); void misc_29(); void misc_30(); - void voice_output( voice_t const* v, int ch ); - void voice_V1( voice_t* const ); - void voice_V2( voice_t* const ); - void voice_V3( voice_t* const ); - void voice_V3a( voice_t* const ); - void voice_V3b( voice_t* const ); - void voice_V3c( voice_t* const ); - void voice_V4( voice_t* const ); - void voice_V5( voice_t* const ); - void voice_V6( voice_t* const ); - void voice_V7( voice_t* const ); - void voice_V8( voice_t* const ); - void voice_V9( voice_t* const ); - void voice_V7_V4_V1( voice_t* const ); - void voice_V8_V5_V2( voice_t* const ); - void voice_V9_V6_V3( voice_t* const ); + void voice_output(voice_t const* v, int ch); + void voice_V1(voice_t* const); + void voice_V2(voice_t* const); + void voice_V3(voice_t* const); + void voice_V3a(voice_t* const); + void voice_V3b(voice_t* const); + void voice_V3c(voice_t* const); + void voice_V4(voice_t* const); + void voice_V5(voice_t* const); + void voice_V6(voice_t* const); + void voice_V7(voice_t* const); + void voice_V8(voice_t* const); + void voice_V9(voice_t* const); + void voice_V7_V4_V1(voice_t* const); + void voice_V8_V5_V2(voice_t* const); + void voice_V9_V6_V3(voice_t* const); - void echo_read( int ch ); - int echo_output( int ch ); - void echo_write( int ch ); + void echo_read(int ch); + int echo_output(int ch); + void echo_write(int ch); void echo_22(); void echo_23(); void echo_24(); @@ -237,7 +266,7 @@ private: void echo_28(); void echo_29(); void echo_30(); - + void soft_reset_common(); }; @@ -245,41 +274,41 @@ private: inline int SPC_DSP::sample_count() const { return (int)(m.out - m.out_begin); } -inline int SPC_DSP::read( int addr ) const +inline int SPC_DSP::read(int addr) const { - assert( (unsigned) addr < register_count ); - return m.regs [addr]; + assert((unsigned) addr < register_count); + return m.regs[addr]; } -inline void SPC_DSP::write( int addr, int data ) +inline void SPC_DSP::write(int addr, int data) { - assert( (unsigned) addr < register_count ); - - m.regs [addr] = (uint8_t) data; - switch ( addr & 0x0F ) + assert((unsigned) addr < register_count); + + m.regs[addr] = (uint8_t)data; + switch (addr & 0x0F) { case v_envx: - m.envx_buf = (uint8_t) data; + m.envx_buf = (uint8_t)data; break; - + case v_outx: - m.outx_buf = (uint8_t) data; + m.outx_buf = (uint8_t)data; break; - + case 0x0C: - if ( addr == r_kon ) - m.new_kon = (uint8_t) data; - - if ( addr == r_endx ) // always cleared, regardless of data written + if (addr == r_kon) + m.new_kon = (uint8_t)data; + + if (addr == r_endx) // always cleared, regardless of data written { m.endx_buf = 0; - m.regs [r_endx] = 0; + m.regs[r_endx] = 0; } break; } } -inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } +inline void SPC_DSP::mute_voices(int mask) { m.mute_mask = mask; } inline bool SPC_DSP::check_kon() { @@ -290,14 +319,20 @@ inline bool SPC_DSP::check_kon() #if !SPC_NO_COPY_STATE_FUNCS -class SPC_State_Copier { +class SPC_State_Copier +{ SPC_DSP::copy_func_t func; unsigned char** buf; public: - SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } - void copy( void* state, size_t size ); - int copy_int( int state, int size ); - void skip( int count ); + SPC_State_Copier(unsigned char** p, SPC_DSP::copy_func_t f) + { + func = f; + buf = p; + } + + void copy(void* state, size_t size); + int copy_int(int state, int size); + void skip(int count); void extra(); }; diff --git a/Core/SPC_Filter.cpp b/Core/SPC_Filter.cpp index efa190e..ebe0218 100644 --- a/Core/SPC_Filter.cpp +++ b/Core/SPC_Filter.cpp @@ -18,7 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" -void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } +void SPC_Filter::clear() { memset(ch, 0, sizeof ch); } SPC_Filter::SPC_Filter() { @@ -27,43 +27,43 @@ SPC_Filter::SPC_Filter() clear(); } -void SPC_Filter::run( short* io, int count ) +void SPC_Filter::run(short* io, int count) { - require( (count & 1) == 0 ); // must be even - + require((count & 1) == 0); // must be even + int const gain = this->gain; int const bass = this->bass; - chan_t* c = &ch [2]; + chan_t* c = &ch[2]; do { // cache in registers int sum = (--c)->sum; int pp1 = c->pp1; - int p1 = c->p1; - - for ( int i = 0; i < count; i += 2 ) + int p1 = c->p1; + + for (int i = 0; i < count; i += 2) { // Low-pass filter (two point FIR with coeffs 0.25, 0.75) - int f = io [i] + p1; - p1 = io [i] * 3; - + int f = io[i] + p1; + p1 = io[i] * 3; + // High-pass filter ("leaky integrator") int delta = f - pp1; pp1 = f; int s = sum >> (gain_bits + 2); sum += (delta * gain) - (sum >> bass); - + // Clamp to 16 bits - if ( (short) s != s ) + if ((short)s != s) s = (s >> 31) ^ 0x7FFF; - - io [i] = (short) s; + + io[i] = (short)s; } - - c->p1 = p1; + + c->p1 = p1; c->pp1 = pp1; c->sum = sum; ++io; } - while ( c != ch ); + while (c != ch); } diff --git a/Core/SPC_Filter.h b/Core/SPC_Filter.h index d5c83cb..a9acd6a 100644 --- a/Core/SPC_Filter.h +++ b/Core/SPC_Filter.h @@ -6,14 +6,15 @@ #include "blargg_common.h" -struct SPC_Filter { +struct SPC_Filter +{ public: - + // Filters count samples of stereo sound in place. Count must be a multiple of 2. typedef short sample_t; - void run( sample_t* io, int count ); - -// Optional features + void run(sample_t* io, int count); + + // Optional features // Clears filter to silence void clear(); @@ -21,27 +22,36 @@ public: // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit // are fine, since output is clamped to 16-bit sample range. enum { gain_unit = 0x100 }; - void set_gain( int gain ); + + void set_gain(int gain); // Sets amount of bass (logarithmic scale) - enum { bass_none = 0 }; - enum { bass_norm = 8 }; // normal amount - enum { bass_max = 31 }; - void set_bass( int bass ); - + enum { bass_none = 0 }; + + enum { bass_norm = 8 }; // normal amount + enum { bass_max = 31 }; + + void set_bass(int bass); + public: SPC_Filter(); BLARGG_DISABLE_NOTHROW private: enum { gain_bits = 8 }; + int gain; int bass; - struct chan_t { int p1, pp1, sum; }; - chan_t ch [2]; + + struct chan_t + { + int p1, pp1, sum; + }; + + chan_t ch[2]; }; -inline void SPC_Filter::set_gain( int g ) { gain = g; } +inline void SPC_Filter::set_gain(int g) { gain = g; } -inline void SPC_Filter::set_bass( int b ) { bass = b; } +inline void SPC_Filter::set_bass(int b) { bass = b; } #endif diff --git a/Core/Sa1.cpp b/Core/Sa1.cpp index 1ec9a72..28f4378 100644 --- a/Core/Sa1.cpp +++ b/Core/Sa1.cpp @@ -25,16 +25,16 @@ Sa1::Sa1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _openBus = 0; _cart = _console->GetCartridge().get(); _snesCpu = _console->GetCpu().get(); - + _iRam = new uint8_t[Sa1::InternalRamSize]; _iRamHandler.reset(new Sa1IRamHandler(_iRam)); console->GetSettings()->InitializeRam(_iRam, 0x800); - + //Register the SA1 in the CPU's memory space ($22xx-$23xx registers) MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); _mappings.RegisterHandler(0x00, 0x3F, 0x2000, 0x2FFF, this); _mappings.RegisterHandler(0x80, 0xBF, 0x2000, 0x2FFF, this); - + cpuMappings->RegisterHandler(0x00, 0x3F, 0x3000, 0x3FFF, _iRamHandler.get()); cpuMappings->RegisterHandler(0x80, 0xBF, 0x3000, 0x3FFF, _iRamHandler.get()); @@ -43,21 +43,25 @@ Sa1::Sa1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _mappings.RegisterHandler(0x00, 0x3F, 0x0000, 0x0FFF, _iRamHandler.get()); _mappings.RegisterHandler(0x80, 0xBF, 0x0000, 0x0FFF, _iRamHandler.get()); - if(_cart->DebugGetSaveRamSize() > 0) { + if (_cart->DebugGetSaveRamSize() > 0) + { _bwRamHandler.reset(new Sa1BwRamHandler(_cart->DebugGetSaveRam(), _cart->DebugGetSaveRamSize(), &_state)); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { //SA-1: 00-3F:6000-7FFF + 80-BF:6000-7FFF _mappings.RegisterHandler(i, i, 0x6000, 0x7FFF, _bwRamHandler.get()); _mappings.RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _bwRamHandler.get()); } - for(int i = 0; i <= 0x0F; i++) { + for (int i = 0; i <= 0x0F; i++) + { //SA-1: 60-6F:0000-FFFF _mappings.RegisterHandler(i + 0x60, i + 0x60, 0x0000, 0xFFFF, _bwRamHandler.get()); } } - vector> &saveRamHandlers = _cart->GetSaveRamHandlers(); - for(unique_ptr &handler : saveRamHandlers) { + vector>& saveRamHandlers = _cart->GetSaveRamHandlers(); + for (unique_ptr& handler : saveRamHandlers) + { _cpuBwRamHandlers.push_back(unique_ptr(new CpuBwRamHandler(handler.get(), &_state, this))); } cpuMappings->RegisterHandler(0x40, 0x4F, 0x0000, 0xFFFF, _cpuBwRamHandlers); @@ -75,317 +79,416 @@ Sa1::~Sa1() void Sa1::Sa1RegisterWrite(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2209: - //SCNT (SNES CPU Control) - _state.CpuMessageReceived = value & 0x0F; - _state.UseCpuNmiVector = (value & 0x10) != 0; - _state.UseCpuIrqVector = (value & 0x40) != 0; - _state.CpuIrqRequested = (value & 0x80) != 0; + switch (addr) + { + case 0x2209: + //SCNT (SNES CPU Control) + _state.CpuMessageReceived = value & 0x0F; + _state.UseCpuNmiVector = (value & 0x10) != 0; + _state.UseCpuIrqVector = (value & 0x40) != 0; + _state.CpuIrqRequested = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x220A: - //CIE (SA-1 CPU Interrupt Enable) - _state.Sa1NmiEnabled = (value & 0x10) != 0; - _state.DmaIrqEnabled = (value & 0x20) != 0; - _state.TimerIrqEnabled = (value & 0x40) != 0; - _state.Sa1IrqEnabled = (value & 0x80) != 0; + case 0x220A: + //CIE (SA-1 CPU Interrupt Enable) + _state.Sa1NmiEnabled = (value & 0x10) != 0; + _state.DmaIrqEnabled = (value & 0x20) != 0; + _state.TimerIrqEnabled = (value & 0x40) != 0; + _state.Sa1IrqEnabled = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x220B: - //CIC (SA-1 CPU Interrupt Clear) - if(value & 0x80) { - _state.Sa1IrqRequested = false; - } - if(value & 0x20) { - _state.DmaIrqFlag = false; - } - if(value & 0x10) { - _state.Sa1NmiRequested = false; - } - ProcessInterrupts(); - break; - - case 0x220C: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF00) | value; break; //SNV (SNES CPU NMI Vector - Low) - case 0x220D: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF) | (value << 8); break; //SNV (SNES CPU NMI Vector - High) + case 0x220B: + //CIC (SA-1 CPU Interrupt Clear) + if (value & 0x80) + { + _state.Sa1IrqRequested = false; + } + if (value & 0x20) + { + _state.DmaIrqFlag = false; + } + if (value & 0x10) + { + _state.Sa1NmiRequested = false; + } + ProcessInterrupts(); + break; - case 0x220E: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF00) | value; break; //SNV (SNES CPU IRQ Vector - Low) - case 0x220F: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF) | (value << 8); break; //SIV (SNES CPU IRQ Vector - High) + case 0x220C: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF00) | value; + break; //SNV (SNES CPU NMI Vector - Low) + case 0x220D: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF) | (value << 8); + break; //SNV (SNES CPU NMI Vector - High) - case 0x2210: - //TMC (H/V Timer Control) - _state.HorizontalTimerEnabled = (value & 0x01) != 0; - _state.VerticalTimerEnabled = (value & 0x02) != 0; - _state.UseLinearTimer = (value & 0x80) != 0; - if(value) { - LogDebug("Using timer"); - } - break; + case 0x220E: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF00) | value; + break; //SNV (SNES CPU IRQ Vector - Low) + case 0x220F: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF) | (value << 8); + break; //SIV (SNES CPU IRQ Vector - High) - case 0x2211: - //CTR (CPU Timer restart) - _state.LinearTimerValue = 0; - LogDebug("Reset timer"); - break; - - case 0x2212: _state.HTimer = (_state.HTimer & 0x0100) | value; LogDebug("Set timer"); break; //HCNT (Timer H-Count - Low) - case 0x2213: _state.HTimer = (_state.HTimer & 0xFF) | ((value & 0x01) << 8); LogDebug("Set timer"); break; //HCNT (Timer H-Count - High) + case 0x2210: + //TMC (H/V Timer Control) + _state.HorizontalTimerEnabled = (value & 0x01) != 0; + _state.VerticalTimerEnabled = (value & 0x02) != 0; + _state.UseLinearTimer = (value & 0x80) != 0; + if (value) + { + LogDebug("Using timer"); + } + break; - case 0x2214: _state.VTimer = (_state.VTimer & 0x0100) | value; LogDebug("Set timer"); break; //VCNT (Timer V-Count - Low) - case 0x2215: _state.VTimer = (_state.VTimer & 0xFF) | ((value & 0x01) << 8); LogDebug("Set timer"); break; //VCNT (Timer V-Count - High) + case 0x2211: + //CTR (CPU Timer restart) + _state.LinearTimerValue = 0; + LogDebug("Reset timer"); + break; - case 0x2225: - //BMAP (SA-1 BW-RAM Address Mapping) - if(_state.Sa1BwBank != (value & 0x7F) || _state.Sa1BwMode != (value & 0x80)) { - _state.Sa1BwBank = value & 0x7F; - _state.Sa1BwMode = (value & 0x80); - UpdateSaveRamMappings(); - } - break; - - case 0x2227: _state.Sa1BwWriteEnabled = (value & 0x80) != 0; break; //CBWE (SA-1 CPU BW-RAM Write Enable) - case 0x222A: _state.Sa1IRamWriteProtect = value; break; //CIWP (SA-1 CPU I-RAM Write Protection) + case 0x2212: _state.HTimer = (_state.HTimer & 0x0100) | value; + LogDebug("Set timer"); + break; //HCNT (Timer H-Count - Low) + case 0x2213: _state.HTimer = (_state.HTimer & 0xFF) | ((value & 0x01) << 8); + LogDebug("Set timer"); + break; //HCNT (Timer H-Count - High) - case 0x2230: - //DCNT (DMA Control) - _state.DmaSrcDevice = (Sa1DmaSrcDevice)(value & 0x03); - _state.DmaDestDevice = (Sa1DmaDestDevice)((value & 0x04) >> 2); - _state.DmaCharConvAuto = (value & 0x10) != 0; - _state.DmaCharConv = (value & 0x20) != 0; - _state.DmaPriority = (value & 0x40) != 0; - _state.DmaEnabled = (value & 0x80) != 0; - if(!_state.DmaEnabled) { - _state.CharConvCounter = 0; - } - break; - - case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: - WriteSharedRegisters(addr, value); - break; + case 0x2214: _state.VTimer = (_state.VTimer & 0x0100) | value; + LogDebug("Set timer"); + break; //VCNT (Timer V-Count - Low) + case 0x2215: _state.VTimer = (_state.VTimer & 0xFF) | ((value & 0x01) << 8); + LogDebug("Set timer"); + break; //VCNT (Timer V-Count - High) - case 0x2238: _state.DmaSize = (_state.DmaSize & 0xFF00) | value; break; //DTC (DMA terminal counter - Low) - case 0x2239: _state.DmaSize = (_state.DmaSize & 0x00FF) | (value << 8); break; //DTC (DMA terminal counter - High) - - case 0x223F: _state.BwRam2BppMode = (value & 0x80) != 0; break; //BBF (Bitmap format) - - case 0x2240: case 0x2241: case 0x2242: case 0x2243: - case 0x2244: case 0x2245: case 0x2246: case 0x2247: - //BRF (Bitmap register file) - _state.BitmapRegister1[addr & 0x07] = value; - if(addr == 0x2247 && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) { - RunCharConvertType2(); - } - break; + case 0x2225: + //BMAP (SA-1 BW-RAM Address Mapping) + if (_state.Sa1BwBank != (value & 0x7F) || _state.Sa1BwMode != (value & 0x80)) + { + _state.Sa1BwBank = value & 0x7F; + _state.Sa1BwMode = (value & 0x80); + UpdateSaveRamMappings(); + } + break; - case 0x2248: case 0x2249: case 0x224A: case 0x224B: - case 0x224C: case 0x224D: case 0x224E: case 0x224F: - //BRF (Bitmap register file) - _state.BitmapRegister2[addr & 0x07] = value; - if(addr == 0x224F && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) { - RunCharConvertType2(); - } - break; + case 0x2227: _state.Sa1BwWriteEnabled = (value & 0x80) != 0; + break; //CBWE (SA-1 CPU BW-RAM Write Enable) + case 0x222A: _state.Sa1IRamWriteProtect = value; + break; //CIWP (SA-1 CPU I-RAM Write Protection) - case 0x2250: - //MCNT (Arithmetic Control) - _state.MathOp = (Sa1MathOp)(value & 0x03); - if(value & 0x02) { - //"Note: Writing Bit1=1 resets the sum to zero." - _state.MathOpResult = 0; - } - break; - case 0x2251: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0xFF00) | value; break; //MA (Arithmetic parameters - Multiplicand/Dividend - Low) - case 0x2252: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0x00FF) | (value << 8); break; //MA (Arithmetic parameters - Multiplicand/Dividend - High) - case 0x2253: _state.MultiplierDivisor = (_state.MultiplierDivisor & 0xFF00) | value; break; //MB (Arithmetic parameters - Multiplier/Divisor - Low) - case 0x2254: - //MB (Arithmetic parameters - Multiplier/Divisor - High) - _state.MultiplierDivisor = (_state.MultiplierDivisor & 0x00FF) | (value << 8); + case 0x2230: + //DCNT (DMA Control) + _state.DmaSrcDevice = (Sa1DmaSrcDevice)(value & 0x03); + _state.DmaDestDevice = (Sa1DmaDestDevice)((value & 0x04) >> 2); + _state.DmaCharConvAuto = (value & 0x10) != 0; + _state.DmaCharConv = (value & 0x20) != 0; + _state.DmaPriority = (value & 0x40) != 0; + _state.DmaEnabled = (value & 0x80) != 0; + if (!_state.DmaEnabled) + { + _state.CharConvCounter = 0; + } + break; - //"Writing to 2254h starts the operation." - CalculateMathOpResult(); - break; - - case 0x2258: - //VBD (Variable length bit processing) - _state.VarLenAutoInc = (value & 0x80) != 0; - _state.VarLenBitCount = value == 0 ? 16 : (value & 0x0F); + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedRegisters(addr, value); + break; - if(!_state.VarLenAutoInc) { - IncVarLenPosition(); - } - break; + case 0x2238: _state.DmaSize = (_state.DmaSize & 0xFF00) | value; + break; //DTC (DMA terminal counter - Low) + case 0x2239: _state.DmaSize = (_state.DmaSize & 0x00FF) | (value << 8); + break; //DTC (DMA terminal counter - High) - case 0x2259: _state.VarLenAddress = (_state.VarLenAddress & 0xFFFF00) | value; break; //VDA (Variable length data address - Low) - case 0x225A: _state.VarLenAddress = (_state.VarLenAddress & 0xFF00FF) | (value << 8); break; //VDA (Variable length data address - Mid) - case 0x225B: - //VDA (Variable length data address - High) - _state.VarLenAddress = (_state.VarLenAddress & 0x00FFFF) | (value << 16); - _state.VarLenCurrentBit = 0; - break; + case 0x223F: _state.BwRam2BppMode = (value & 0x80) != 0; + break; //BBF (Bitmap format) + + case 0x2240: + case 0x2241: + case 0x2242: + case 0x2243: + case 0x2244: + case 0x2245: + case 0x2246: + case 0x2247: + //BRF (Bitmap register file) + _state.BitmapRegister1[addr & 0x07] = value; + if (addr == 0x2247 && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) + { + RunCharConvertType2(); + } + break; + + case 0x2248: + case 0x2249: + case 0x224A: + case 0x224B: + case 0x224C: + case 0x224D: + case 0x224E: + case 0x224F: + //BRF (Bitmap register file) + _state.BitmapRegister2[addr & 0x07] = value; + if (addr == 0x224F && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) + { + RunCharConvertType2(); + } + break; + + case 0x2250: + //MCNT (Arithmetic Control) + _state.MathOp = (Sa1MathOp)(value & 0x03); + if (value & 0x02) + { + //"Note: Writing Bit1=1 resets the sum to zero." + _state.MathOpResult = 0; + } + break; + case 0x2251: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0xFF00) | value; + break; //MA (Arithmetic parameters - Multiplicand/Dividend - Low) + case 0x2252: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0x00FF) | (value << 8); + break; //MA (Arithmetic parameters - Multiplicand/Dividend - High) + case 0x2253: _state.MultiplierDivisor = (_state.MultiplierDivisor & 0xFF00) | value; + break; //MB (Arithmetic parameters - Multiplier/Divisor - Low) + case 0x2254: + //MB (Arithmetic parameters - Multiplier/Divisor - High) + _state.MultiplierDivisor = (_state.MultiplierDivisor & 0x00FF) | (value << 8); + + //"Writing to 2254h starts the operation." + CalculateMathOpResult(); + break; + + case 0x2258: + //VBD (Variable length bit processing) + _state.VarLenAutoInc = (value & 0x80) != 0; + _state.VarLenBitCount = value == 0 ? 16 : (value & 0x0F); + + if (!_state.VarLenAutoInc) + { + IncVarLenPosition(); + } + break; + + case 0x2259: _state.VarLenAddress = (_state.VarLenAddress & 0xFFFF00) | value; + break; //VDA (Variable length data address - Low) + case 0x225A: _state.VarLenAddress = (_state.VarLenAddress & 0xFF00FF) | (value << 8); + break; //VDA (Variable length data address - Mid) + case 0x225B: + //VDA (Variable length data address - High) + _state.VarLenAddress = (_state.VarLenAddress & 0x00FFFF) | (value << 16); + _state.VarLenCurrentBit = 0; + break; } } void Sa1::CpuRegisterWrite(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2200: - //CCNT (SA-1 CPU Control) - if(!(value & 0x20) && _state.Sa1Reset) { - //Reset the CPU, and sync cycle count - _cpu->Reset(); - _cpu->IncreaseCycleCount(_memoryManager->GetMasterClock() / 2); - } + switch (addr) + { + case 0x2200: + //CCNT (SA-1 CPU Control) + if (!(value & 0x20) && _state.Sa1Reset) + { + //Reset the CPU, and sync cycle count + _cpu->Reset(); + _cpu->IncreaseCycleCount(_memoryManager->GetMasterClock() / 2); + } - _state.Sa1MessageReceived = value & 0x0F; - _state.Sa1NmiRequested = (value & 0x10) != 0; - _state.Sa1Reset = (value & 0x20) != 0; - _state.Sa1Wait = (value & 0x40) != 0; - _state.Sa1IrqRequested = (value & 0x80) != 0; + _state.Sa1MessageReceived = value & 0x0F; + _state.Sa1NmiRequested = (value & 0x10) != 0; + _state.Sa1Reset = (value & 0x20) != 0; + _state.Sa1Wait = (value & 0x40) != 0; + _state.Sa1IrqRequested = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x2201: - //SIE (SNES CPU Interrupt Enable) - _state.CpuIrqEnabled = (value & 0x80) != 0; - _state.CharConvIrqEnabled = (value & 0x20) != 0; + case 0x2201: + //SIE (SNES CPU Interrupt Enable) + _state.CpuIrqEnabled = (value & 0x80) != 0; + _state.CharConvIrqEnabled = (value & 0x20) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x2202: - //SIC (SNES CPU Interrupt Clear) - if(value & 0x80) { - _state.CpuIrqRequested = false; - } - if(value & 0x20) { - _state.CharConvIrqFlag = false; - } - ProcessInterrupts(); - break; + case 0x2202: + //SIC (SNES CPU Interrupt Clear) + if (value & 0x80) + { + _state.CpuIrqRequested = false; + } + if (value & 0x20) + { + _state.CharConvIrqFlag = false; + } + ProcessInterrupts(); + break; - case 0x2203: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF00) | value; break; //CRV (SA-1 Reset Vector - Low) - case 0x2204: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF) | (value << 8); break; //CRV (SA-1 Reset Vector - High) + case 0x2203: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF00) | value; + break; //CRV (SA-1 Reset Vector - Low) + case 0x2204: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF) | (value << 8); + break; //CRV (SA-1 Reset Vector - High) - case 0x2205: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF00) | value; break; //CRV (SA-1 NMI Vector - Low) - case 0x2206: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF) | (value << 8); break; //CRV (SA-1 NMI Vector - High) + case 0x2205: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF00) | value; + break; //CRV (SA-1 NMI Vector - Low) + case 0x2206: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF) | (value << 8); + break; //CRV (SA-1 NMI Vector - High) - case 0x2207: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF00) | value; break; //CRV (SA-1 IRQ Vector - Low) - case 0x2208: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF) | (value << 8); break; //CRV (SA-1 IRQ Vector - High) + case 0x2207: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF00) | value; + break; //CRV (SA-1 IRQ Vector - Low) + case 0x2208: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF) | (value << 8); + break; //CRV (SA-1 IRQ Vector - High) - case 0x2220: UpdateBank(0, value); break; //CXB (MMC Bank C) - case 0x2221: UpdateBank(1, value); break; //DXB (MMC Bank D) - case 0x2222: UpdateBank(2, value); break; //EXB (MMC Bank E) - case 0x2223: UpdateBank(3, value); break; //FXB (MMC Bank F) + case 0x2220: UpdateBank(0, value); + break; //CXB (MMC Bank C) + case 0x2221: UpdateBank(1, value); + break; //DXB (MMC Bank D) + case 0x2222: UpdateBank(2, value); + break; //EXB (MMC Bank E) + case 0x2223: UpdateBank(3, value); + break; //FXB (MMC Bank F) - case 0x2224: - //BMAPS (SNES CPU BW-RAM Address Mapping) - if(_state.CpuBwBank != (value & 0x1F)) { - _state.CpuBwBank = value & 0x1F; - UpdateSaveRamMappings(); - } - break; + case 0x2224: + //BMAPS (SNES CPU BW-RAM Address Mapping) + if (_state.CpuBwBank != (value & 0x1F)) + { + _state.CpuBwBank = value & 0x1F; + UpdateSaveRamMappings(); + } + break; - case 0x2226: _state.CpuBwWriteEnabled = (value & 0x80) != 0; break; //SBWE (SNES CPU BW-RAM Write Enable) - - case 0x2228: _state.BwWriteProtectedArea = (value & 0x0F); break; //BWPA (SNES CPU BW-RAM Write Protected Area) + case 0x2226: _state.CpuBwWriteEnabled = (value & 0x80) != 0; + break; //SBWE (SNES CPU BW-RAM Write Enable) - case 0x2229: _state.CpuIRamWriteProtect = value; break; //SIWP (SNES CPU I-RAM Write Protection) + case 0x2228: _state.BwWriteProtectedArea = (value & 0x0F); + break; //BWPA (SNES CPU BW-RAM Write Protected Area) - case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: - WriteSharedRegisters(addr, value); - break; + case 0x2229: _state.CpuIRamWriteProtect = value; + break; //SIWP (SNES CPU I-RAM Write Protection) + + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedRegisters(addr, value); + break; } } void Sa1::WriteSharedRegisters(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2231: - //CDMA (Character conversion DMA parameters) (Shared with SNES CPU) - _state.CharConvFormat = std::min(value & 0x03, 2); - switch(_state.CharConvFormat) { - case 0: _state.CharConvBpp = 8; break; - case 1: _state.CharConvBpp = 4; break; - case 2: _state.CharConvBpp = 2; break; - } - _state.CharConvWidth = std::min((value & 0x1C) >> 2, 5); - - if(value & 0x80) { - //End of character conversion type 1 - _state.CharConvDmaActive = false; - } + switch (addr) + { + case 0x2231: + //CDMA (Character conversion DMA parameters) (Shared with SNES CPU) + _state.CharConvFormat = std::min(value & 0x03, 2); + switch (_state.CharConvFormat) + { + case 0: _state.CharConvBpp = 8; break; - - case 0x2232: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFFFF00) | value; break; //SDA (DMA source start address - Low) (Shared with SNES CPU) - case 0x2233: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFF00FF) | (value << 8); break; //SDA (DMA source start address - Mid) (Shared with SNES CPU) - case 0x2234: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0x00FFFF) | (value << 16); break; //SDA (DMA source start address - High) (Shared with SNES CPU) - - case 0x2235: _state.DmaDestAddr = (_state.DmaDestAddr & 0xFFFF00) | value; break; //DDA (DMA dest start address - Low) (Shared with SNES CPU) - case 0x2236: - //DDA (DMA dest start address - Mid) (Shared with SNES CPU) - _state.DmaDestAddr = (_state.DmaDestAddr & 0xFF00FF) | (value << 8); - if(_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { - _state.DmaRunning = true; - } else if(_state.DmaCharConv && _state.DmaCharConvAuto) { - _state.CharConvDmaActive = true; - _state.CharConvIrqFlag = true; - ProcessInterrupts(); - } - break; - - case 0x2237: - //DDA (DMA dest start address - High) (Shared with SNES CPU) - _state.DmaDestAddr = (_state.DmaDestAddr & 0x00FFFF) | (value << 16); - if(_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { - _state.DmaRunning = true; - } + case 1: _state.CharConvBpp = 4; break; + case 2: _state.CharConvBpp = 2; + break; + } + _state.CharConvWidth = std::min((value & 0x1C) >> 2, 5); + + if (value & 0x80) + { + //End of character conversion type 1 + _state.CharConvDmaActive = false; + } + break; + + case 0x2232: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFFFF00) | value; + break; //SDA (DMA source start address - Low) (Shared with SNES CPU) + case 0x2233: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFF00FF) | (value << 8); + break; //SDA (DMA source start address - Mid) (Shared with SNES CPU) + case 0x2234: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0x00FFFF) | (value << 16); + break; //SDA (DMA source start address - High) (Shared with SNES CPU) + + case 0x2235: _state.DmaDestAddr = (_state.DmaDestAddr & 0xFFFF00) | value; + break; //DDA (DMA dest start address - Low) (Shared with SNES CPU) + case 0x2236: + //DDA (DMA dest start address - Mid) (Shared with SNES CPU) + _state.DmaDestAddr = (_state.DmaDestAddr & 0xFF00FF) | (value << 8); + if (_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { + _state.DmaRunning = true; + } + else if (_state.DmaCharConv && _state.DmaCharConvAuto) + { + _state.CharConvDmaActive = true; + _state.CharConvIrqFlag = true; + ProcessInterrupts(); + } + break; + + case 0x2237: + //DDA (DMA dest start address - High) (Shared with SNES CPU) + _state.DmaDestAddr = (_state.DmaDestAddr & 0x00FFFF) | (value << 16); + if (_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { + _state.DmaRunning = true; + } + break; } } uint8_t Sa1::Sa1RegisterRead(uint16_t addr) { - switch(addr) { - case 0x2301: - //CFR (SA-1 Status Flags) - return ( - _state.Sa1MessageReceived | - (_state.Sa1NmiRequested << 4) | - (_state.DmaIrqFlag << 5) | - //TODO: Timer irq flag - (_state.Sa1IrqRequested << 7) - ); - - case 0x2302: break; //HCR (SA-1 H Counter read - Low) - case 0x2303: break; //HCR (SA-1 H Counter read - High) - - case 0x2304: break; //VCR (SA-1 V Counter read - Low) - case 0x2305: break; //VCR (SA-1 V Counter read - High) - - case 0x2306: return _state.MathOpResult & 0xFF; //MR (Arithmetic result) - case 0x2307: return (_state.MathOpResult >> 8) & 0xFF; //MR (Arithmetic result) - case 0x2308: return (_state.MathOpResult >> 16) & 0xFF; break; //MR (Arithmetic result) - case 0x2309: return (_state.MathOpResult >> 24) & 0xFF; break; //MR (Arithmetic result) - case 0x230A: return (_state.MathOpResult >> 32) & 0xFF; break; //MR (Arithmetic result) + switch (addr) + { + case 0x2301: + //CFR (SA-1 Status Flags) + return ( + _state.Sa1MessageReceived | + (_state.Sa1NmiRequested << 4) | + (_state.DmaIrqFlag << 5) | + //TODO: Timer irq flag + (_state.Sa1IrqRequested << 7) + ); - case 0x230B: return _state.MathOverflow; break; //OF (Arithmetic overflow flag) + case 0x2302: break; //HCR (SA-1 H Counter read - Low) + case 0x2303: break; //HCR (SA-1 H Counter read - High) - case 0x230C: { + case 0x2304: break; //VCR (SA-1 V Counter read - Low) + case 0x2305: break; //VCR (SA-1 V Counter read - High) + + case 0x2306: return _state.MathOpResult & 0xFF; //MR (Arithmetic result) + case 0x2307: return (_state.MathOpResult >> 8) & 0xFF; //MR (Arithmetic result) + case 0x2308: return (_state.MathOpResult >> 16) & 0xFF; + break; //MR (Arithmetic result) + case 0x2309: return (_state.MathOpResult >> 24) & 0xFF; + break; //MR (Arithmetic result) + case 0x230A: return (_state.MathOpResult >> 32) & 0xFF; + break; //MR (Arithmetic result) + + case 0x230B: return _state.MathOverflow; + break; //OF (Arithmetic overflow flag) + + case 0x230C: + { //VDP (Variable length data port - Low) - uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1(_state.VarLenAddress + 2) << 16); + uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1( + _state.VarLenAddress + 2) << 16); return data >> _state.VarLenCurrentBit; } - case 0x230D: { + case 0x230D: + { //VDP (Variable length data port - High) - uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1(_state.VarLenAddress + 2) << 16); + uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1( + _state.VarLenAddress + 2) << 16); uint8_t value = data >> (_state.VarLenCurrentBit + 8); - if(_state.VarLenAutoInc) { + if (_state.VarLenAutoInc) + { IncVarLenPosition(); } return value; @@ -399,18 +502,19 @@ uint8_t Sa1::Sa1RegisterRead(uint16_t addr) uint8_t Sa1::CpuRegisterRead(uint16_t addr) { - switch(addr) { - case 0x2300: - //SFR (SNES CPU Status Flags) - return ( - _state.CpuMessageReceived | - (_state.UseCpuNmiVector << 4) | - (_state.CharConvIrqFlag << 5) | - (_state.UseCpuIrqVector << 6) | - (_state.CpuIrqRequested << 7) - ); + switch (addr) + { + case 0x2300: + //SFR (SNES CPU Status Flags) + return ( + _state.CpuMessageReceived | + (_state.UseCpuNmiVector << 4) | + (_state.CharConvIrqFlag << 5) | + (_state.UseCpuIrqVector << 6) | + (_state.CpuIrqRequested << 7) + ); - case 0x230E: break; //VC (Version code register) + case 0x230E: break; //VC (Version code register) } LogDebug("[Debug] CPU - missing register: $" + HexUtilities::ToHex(addr)); @@ -420,43 +524,55 @@ uint8_t Sa1::CpuRegisterRead(uint16_t addr) void Sa1::ProcessInterrupts() { - if((_state.Sa1IrqRequested && _state.Sa1IrqEnabled) || (_state.DmaIrqFlag && _state.DmaIrqEnabled)) { + if ((_state.Sa1IrqRequested && _state.Sa1IrqEnabled) || (_state.DmaIrqFlag && _state.DmaIrqEnabled)) + { _cpu->SetIrqSource(IrqSource::Coprocessor); - } else { + } + else + { _cpu->ClearIrqSource(IrqSource::Coprocessor); } _cpu->SetNmiFlag(_state.Sa1NmiRequested && _state.Sa1NmiEnabled); - if((_state.CpuIrqRequested && _state.CpuIrqEnabled) || (_state.CharConvIrqFlag && _state.CharConvIrqEnabled)) { + if ((_state.CpuIrqRequested && _state.CpuIrqEnabled) || (_state.CharConvIrqFlag && _state.CharConvIrqEnabled)) + { _snesCpu->SetIrqSource(IrqSource::Coprocessor); - } else { + } + else + { _snesCpu->ClearIrqSource(IrqSource::Coprocessor); } } void Sa1::WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); _console->ProcessMemoryWrite(addr, value, type); - if(handler) { + if (handler) + { _lastAccessMemType = handler->GetMemoryType(); _openBus = value; handler->Write(addr, value); - } else { + } + else + { LogDebug("[Debug] Write SA1 - missing handler: $" + HexUtilities::ToHex(addr)); } } uint8_t Sa1::ReadSa1(uint32_t addr, MemoryOperationType type) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); uint8_t value; - if(handler) { + if (handler) + { value = handler->Read(addr); _lastAccessMemType = handler->GetMemoryType(); _openBus = value; - } else { + } + else + { value = _openBus; LogDebug("[Debug] Read SA1 - missing handler: $" + HexUtilities::ToHex(addr)); } @@ -475,7 +591,7 @@ uint8_t Sa1::Peek(uint32_t addr) return 0; } -void Sa1::PeekBlock(uint32_t addr, uint8_t *output) +void Sa1::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } @@ -487,19 +603,25 @@ void Sa1::Write(uint32_t addr, uint8_t value) AddressInfo Sa1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void Sa1::Run() { uint64_t targetCycle = _memoryManager->GetMasterClock() / 2; - while(_cpu->GetCycleCount() < targetCycle) { - if(_state.Sa1Wait || _state.Sa1Reset) { + while (_cpu->GetCycleCount() < targetCycle) + { + if (_state.Sa1Wait || _state.Sa1Reset) + { _cpu->IncreaseCycleCount<1>(); - } else if(_state.DmaRunning) { + } + else if (_state.DmaRunning) + { RunDma(); - } else { + } + else + { _cpu->Exec(); } } @@ -517,45 +639,64 @@ void Sa1::WriteBwRam(uint32_t addr, uint8_t value) void Sa1::RunDma() { - if(_state.DmaSize > 0) { + if (_state.DmaSize > 0) + { _state.DmaSize--; - - if(_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { + + if (_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::PrgRom || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::PrgRom || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); } } WriteInternalRam(_state.DmaDestAddr, ReadSa1(_state.DmaSrcAddr)); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { _cpu->IncreaseCycleCount<2>(); - - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<2>(); } WriteBwRam(_state.DmaDestAddr, ReadSa1(_state.DmaSrcAddr)); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::BwRam && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::BwRam && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { _cpu->IncreaseCycleCount<2>(); - - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<1>(); } } - WriteInternalRam(_state.DmaDestAddr, _cart->DebugGetSaveRam()[_state.DmaSrcAddr & (_cart->DebugGetSaveRamSize() - 1)]); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::InternalRam && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { + WriteInternalRam(_state.DmaDestAddr, + _cart->DebugGetSaveRam()[_state.DmaSrcAddr & (_cart->DebugGetSaveRamSize() - 1)]); + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::InternalRam && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { _cpu->IncreaseCycleCount<2>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<1>(); } } @@ -567,7 +708,8 @@ void Sa1::RunDma() _state.DmaDestAddr++; } - if(_state.DmaSize == 0) { + if (_state.DmaSize == 0) + { _state.DmaRunning = false; _state.DmaIrqFlag = true; ProcessInterrupts(); @@ -576,7 +718,8 @@ void Sa1::RunDma() void Sa1::UpdateBank(uint8_t index, uint8_t value) { - if(_state.Banks[index] != value) { + if (_state.Banks[index] != value) + { _state.Banks[index] = value; UpdatePrgRomMappings(); } @@ -584,15 +727,20 @@ void Sa1::UpdateBank(uint8_t index, uint8_t value) void Sa1::UpdatePrgRomMappings() { - vector> &prgRomHandlers = _cart->GetPrgRomHandlers(); + vector>& prgRomHandlers = _cart->GetPrgRomHandlers(); MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { MemoryMappings* mappings = i == 0 ? &_mappings : cpuMappings; - mappings->RegisterHandler(0x00, 0x1F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[0] & 0x80) ? (_state.Banks[0] & 0x07) * 256 : 0); - mappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[1] & 0x80) ? (_state.Banks[1] & 0x07) * 256 : 256); - mappings->RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[2] & 0x80) ? (_state.Banks[2] & 0x07) * 256 : 512); - mappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[3] & 0x80) ? (_state.Banks[3] & 0x07) * 256 : 768); + mappings->RegisterHandler(0x00, 0x1F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[0] & 0x80) ? (_state.Banks[0] & 0x07) * 256 : 0); + mappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[1] & 0x80) ? (_state.Banks[1] & 0x07) * 256 : 256); + mappings->RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[2] & 0x80) ? (_state.Banks[2] & 0x07) * 256 : 512); + mappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[3] & 0x80) ? (_state.Banks[3] & 0x07) * 256 : 768); mappings->RegisterHandler(0xC0, 0xCF, 0x0000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[0] & 0x07) * 256); mappings->RegisterHandler(0xD0, 0xDF, 0x0000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[1] & 0x07) * 256); @@ -612,12 +760,14 @@ void Sa1::UpdateVectorMappings() void Sa1::UpdateSaveRamMappings() { - vector> &saveRamHandlers = _cart->GetSaveRamHandlers(); - if(saveRamHandlers.size() > 0) { + vector>& saveRamHandlers = _cart->GetSaveRamHandlers(); + if (saveRamHandlers.size() > 0) + { MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); uint32_t bank1 = (_state.CpuBwBank * 2) % saveRamHandlers.size(); uint32_t bank2 = (_state.CpuBwBank * 2 + 1) % saveRamHandlers.size(); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { //S-CPU: 00-3F:6000-7FFF + 80-BF:6000-7FFF cpuMappings->RegisterHandler(i, i, 0x6000, 0x6FFF, saveRamHandlers[bank1].get()); cpuMappings->RegisterHandler(i, i, 0x7000, 0x7FFF, saveRamHandlers[bank2].get()); @@ -636,27 +786,38 @@ void Sa1::IncVarLenPosition() void Sa1::CalculateMathOpResult() { - if((int)_state.MathOp & (int)Sa1MathOp::Sum) { - uint64_t result = _state.MathOpResult + ((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor); + if ((int)_state.MathOp & (int)Sa1MathOp::Sum) + { + uint64_t result = _state.MathOpResult + ((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor + ); _state.MathOverflow = (result >> 33) & 0x80; - + //Keep 40 bits _state.MathOpResult = result & 0xFFFFFFFFFF; _state.MultiplierDivisor = 0; - } else { - if(_state.MathOp == Sa1MathOp::Mul) { + } + else + { + if (_state.MathOp == Sa1MathOp::Mul) + { _state.MathOpResult = (uint32_t)((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor); //"The value in this register gets destroyed after both multiplication and division." _state.MultiplierDivisor = 0; - } else { - if(_state.MultiplierDivisor == 0) { + } + else + { + if (_state.MultiplierDivisor == 0) + { //Division by 0 returns 0, remainder 0 _state.MathOpResult = 0; - } else { + } + else + { int16_t dividend = _state.MultiplicandDividend; uint16_t remainder = dividend % _state.MultiplierDivisor; - if(dividend < 0) { + if (dividend < 0) + { remainder += _state.MultiplierDivisor; } uint16_t result = (dividend - remainder) / _state.MultiplierDivisor; @@ -675,8 +836,9 @@ void Sa1::CalculateMathOpResult() uint8_t Sa1::ReadCharConvertType1(uint32_t addr) { uint8_t mask = (_state.CharConvBpp * 8) - 1; - - if((addr & mask) == 0) { + + if ((addr & mask) == 0) + { //Trying to read the first byte of a new tile, convert it and write its contents to IRAM uint8_t* bwRam = _cart->DebugGetSaveRam(); uint32_t bwRamMask = _cart->DebugGetSaveRamSize() - 1; @@ -688,25 +850,30 @@ uint8_t Sa1::ReadCharConvertType1(uint32_t addr) uint32_t tileY = (tileNumber >> _state.CharConvWidth); uint32_t srcAddr = _state.DmaSrcAddr + tileY * 8 * bytesPerLine + tileX * _state.CharConvBpp; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { //For each row, get the original pixels (in a packed format, 4 pixels per byte in 2bpp, 2 pixels per byte in 4bpp, etc.) uint64_t data = 0; - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { data |= (uint64_t)bwRam[(srcAddr + i) & bwRamMask] << (i * 8); } srcAddr += bytesPerLine; uint8_t result[8] = {}; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { //For each column (pixels in the tile), convert to VRAM format - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { result[i] |= (data & 0x01) << (7 - x); data >>= 1; } } //Copy all converted bytes to IRAM (in PPU VRAM format) - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { uint8_t offset = (y << 1) + ((i >> 1) << 4) + (i & 0x01); _iRam[(_state.DmaDestAddr + offset) & 0x7FF] = result[i]; } @@ -726,10 +893,12 @@ void Sa1::RunCharConvertType2() dest += (_state.CharConvCounter & 0x08) * _state.CharConvBpp; //number of bytes per tile row //Convert 1 pixel per byte format (no matter BPP) to VRAM format - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { //For each bitplane, grab the matching bit for all 8 pixels and convert to VRAM format uint8_t value = 0; - for(int j = 0; j < 8; j++) { + for (int j = 0; j < 8; j++) + { value |= ((bmpRegs[j] >> i) & 0x01) << (7 - j); } @@ -799,10 +968,11 @@ CpuState Sa1::GetCpuState() uint16_t Sa1::ReadVector(uint16_t vector) { - switch(vector) { - case Sa1Cpu::NmiVector: return _state.Sa1NmiVector; - case Sa1Cpu::ResetVector: return _state.Sa1ResetVector; - case Sa1Cpu::IrqVector: return _state.Sa1IrqVector; + switch (vector) + { + case Sa1Cpu::NmiVector: return _state.Sa1NmiVector; + case Sa1Cpu::ResetVector: return _state.Sa1ResetVector; + case Sa1Cpu::IrqVector: return _state.Sa1IrqVector; } //BRK/COP vectors are taken from ROM @@ -818,7 +988,8 @@ MemoryMappings* Sa1::GetMemoryMappings() void Sa1::LoadBattery() { - if(_cpuBwRamHandlers.empty()) { + if (_cpuBwRamHandlers.empty()) + { //When there is no actual save RAM and the battery flag is set, IRAM is backed up instead //Used by Pachi-Slot Monogatari - PAL Kougyou Special _console->GetBatteryManager()->LoadBattery(".srm", _iRam, Sa1::InternalRamSize); @@ -827,25 +998,34 @@ void Sa1::LoadBattery() void Sa1::SaveBattery() { - if(_cpuBwRamHandlers.empty()) { + if (_cpuBwRamHandlers.empty()) + { _console->GetBatteryManager()->SaveBattery(".srm", _iRam, Sa1::InternalRamSize); } } -void Sa1::Serialize(Serializer &s) +void Sa1::Serialize(Serializer& s) { s.Stream(_cpu.get()); s.Stream( - _state.Sa1ResetVector, _state.Sa1IrqVector, _state.Sa1NmiVector, _state.Sa1IrqRequested, _state.Sa1IrqEnabled, _state.Sa1NmiRequested, _state.Sa1NmiEnabled, - _state.Sa1Wait, _state.Sa1Reset, _state.DmaIrqEnabled, _state.TimerIrqEnabled, _state.Sa1MessageReceived, _state.CpuMessageReceived, _state.CpuIrqVector, - _state.CpuNmiVector, _state.UseCpuIrqVector, _state.UseCpuNmiVector, _state.CpuIrqRequested, _state.CpuIrqEnabled, _state.CharConvIrqFlag, _state.CharConvIrqEnabled, - _state.CpuBwBank, _state.CpuBwWriteEnabled, _state.Sa1BwBank, _state.Sa1BwMode, _state.Sa1BwWriteEnabled, _state.BwWriteProtectedArea, _state.BwRam2BppMode, - _state.CpuIRamWriteProtect, _state.Sa1IRamWriteProtect, _state.DmaSrcAddr, _state.DmaDestAddr, _state.DmaSize, _state.DmaEnabled, _state.DmaPriority, - _state.DmaCharConv, _state.DmaCharConvAuto, _state.DmaDestDevice, _state.DmaSrcDevice, _state.DmaRunning, _state.DmaIrqFlag, _state.HorizontalTimerEnabled, - _state.VerticalTimerEnabled, _state.UseLinearTimer, _state.HTimer, _state.VTimer, _state.LinearTimerValue, _state.MathOp, _state.MultiplicandDividend, - _state.MultiplierDivisor, _state.MathOpResult, _state.MathOverflow, _state.VarLenAutoInc, _state.VarLenBitCount, _state.VarLenAddress, + _state.Sa1ResetVector, _state.Sa1IrqVector, _state.Sa1NmiVector, _state.Sa1IrqRequested, _state.Sa1IrqEnabled, + _state.Sa1NmiRequested, _state.Sa1NmiEnabled, + _state.Sa1Wait, _state.Sa1Reset, _state.DmaIrqEnabled, _state.TimerIrqEnabled, _state.Sa1MessageReceived, + _state.CpuMessageReceived, _state.CpuIrqVector, + _state.CpuNmiVector, _state.UseCpuIrqVector, _state.UseCpuNmiVector, _state.CpuIrqRequested, _state.CpuIrqEnabled, + _state.CharConvIrqFlag, _state.CharConvIrqEnabled, + _state.CpuBwBank, _state.CpuBwWriteEnabled, _state.Sa1BwBank, _state.Sa1BwMode, _state.Sa1BwWriteEnabled, + _state.BwWriteProtectedArea, _state.BwRam2BppMode, + _state.CpuIRamWriteProtect, _state.Sa1IRamWriteProtect, _state.DmaSrcAddr, _state.DmaDestAddr, _state.DmaSize, + _state.DmaEnabled, _state.DmaPriority, + _state.DmaCharConv, _state.DmaCharConvAuto, _state.DmaDestDevice, _state.DmaSrcDevice, _state.DmaRunning, + _state.DmaIrqFlag, _state.HorizontalTimerEnabled, + _state.VerticalTimerEnabled, _state.UseLinearTimer, _state.HTimer, _state.VTimer, _state.LinearTimerValue, + _state.MathOp, _state.MultiplicandDividend, + _state.MultiplierDivisor, _state.MathOpResult, _state.MathOverflow, _state.VarLenAutoInc, _state.VarLenBitCount, + _state.VarLenAddress, _state.Banks[0], _state.Banks[1], _state.Banks[2], _state.Banks[3], _state.BitmapRegister1[0], _state.BitmapRegister1[1], _state.BitmapRegister1[2], _state.BitmapRegister1[3], _state.BitmapRegister1[4], _state.BitmapRegister1[5], _state.BitmapRegister1[6], _state.BitmapRegister1[7], @@ -858,7 +1038,8 @@ void Sa1::Serialize(Serializer &s) s.Stream(_lastAccessMemType, _openBus); s.StreamArray(_iRam, Sa1::InternalRamSize); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { UpdatePrgRomMappings(); UpdateSaveRamMappings(); ProcessInterrupts(); diff --git a/Core/Sa1.h b/Core/Sa1.h index e709d48..415b8fd 100644 --- a/Core/Sa1.h +++ b/Core/Sa1.h @@ -26,18 +26,18 @@ private: Sa1State _state = {}; uint8_t* _iRam; - + SnesMemoryType _lastAccessMemType; uint8_t _openBus; unique_ptr _iRamHandler; unique_ptr _bwRamHandler; unique_ptr _cpuVectorHandler; - + vector> _cpuBwRamHandlers; MemoryMappings _mappings; - + void UpdateBank(uint8_t index, uint8_t value); void UpdatePrgRomMappings(); void UpdateVectorMappings(); @@ -46,7 +46,7 @@ private: void IncVarLenPosition(); void CalculateMathOpResult(); void RunCharConvertType2(); - + void ProcessInterrupts(); void RunDma(); @@ -61,7 +61,7 @@ private: public: Sa1(Console* console); virtual ~Sa1(); - + void WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type); uint8_t ReadSa1(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read); @@ -71,13 +71,13 @@ public: uint8_t ReadCharConvertType1(uint32_t addr); // Inherited via BaseCoprocessor - void Serialize(Serializer & s) override; + void Serialize(Serializer& s) override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - + void Run() override; void Reset() override; diff --git a/Core/Sa1BwRamHandler.h b/Core/Sa1BwRamHandler.h index ac6ae5c..bb80d84 100644 --- a/Core/Sa1BwRamHandler.h +++ b/Core/Sa1BwRamHandler.h @@ -11,7 +11,7 @@ class Sa1BwRamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; uint32_t _mask; Sa1State* _state; @@ -22,14 +22,20 @@ private: __forceinline uint8_t InternalRead(uint32_t addr) { - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { return ReadBitmapMode(addr - 0x600000); - } else { + } + else + { addr = GetBwRamAddress(addr); - if(_state->Sa1BwMode) { + if (_state->Sa1BwMode) + { //Bitmap mode is enabled return ReadBitmapMode(addr); - } else { + } + else + { //Return regular memory content return _ram[addr & _mask]; } @@ -54,22 +60,29 @@ public: return InternalRead(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = InternalRead(addr + i); } } void Write(uint32_t addr, uint8_t value) override { - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { WriteBitmapMode(addr - 0x600000, value); - } else { + } + else + { addr = GetBwRamAddress(addr); - if(_state->Sa1BwMode) { + if (_state->Sa1BwMode) + { WriteBitmapMode(addr, value); - } else { + } + else + { _ram[addr & _mask] = value; } } @@ -77,20 +90,26 @@ public: uint8_t ReadBitmapMode(uint32_t addr) { - if(_state->BwRam2BppMode) { + if (_state->BwRam2BppMode) + { return (_ram[(addr >> 2) & _mask] >> ((addr & 0x03) * 2)) & 0x03; - } else { + } + else + { return (_ram[(addr >> 1) & _mask] >> ((addr & 0x01) * 4)) & 0x0F; } } void WriteBitmapMode(uint32_t addr, uint8_t value) { - if(_state->BwRam2BppMode) { + if (_state->BwRam2BppMode) + { uint8_t shift = (addr & 0x03) * 2; addr = (addr >> 2) & _mask; _ram[addr] = (_ram[addr] & ~(0x03 << shift)) | ((value & 0x03) << shift); - } else { + } + else + { uint8_t shift = (addr & 0x01) * 4; addr = (addr >> 1) & _mask; _ram[addr] = (_ram[addr] & ~(0x0F << shift)) | ((value & 0x0F) << shift); @@ -100,12 +119,15 @@ public: AddressInfo GetAbsoluteAddress(uint32_t addr) override { AddressInfo info; - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { info.Address = ((addr - 0x600000) >> (_state->BwRam2BppMode ? 2 : 1)) & _mask; - } else { + } + else + { info.Address = GetBwRamAddress(addr) & _mask; } info.Type = SnesMemoryType::SaveRam; return info; } -}; \ No newline at end of file +}; diff --git a/Core/Sa1Cpu.cpp b/Core/Sa1Cpu.cpp index 27b3b18..70d8746 100644 --- a/Core/Sa1Cpu.cpp +++ b/Core/Sa1Cpu.cpp @@ -27,30 +27,36 @@ void Sa1Cpu::Exec() { _immediateMode = false; - switch(_state.StopState) { - case CpuStopState::Running: RunOp(); break; - case CpuStopState::Stopped: - //STP was executed, CPU no longer executes any code - _state.CycleCount++; - return; + switch (_state.StopState) + { + case CpuStopState::Running: RunOp(); + break; + case CpuStopState::Stopped: + //STP was executed, CPU no longer executes any code + _state.CycleCount++; + return; - case CpuStopState::WaitingForIrq: - //WAI + case CpuStopState::WaitingForIrq: + //WAI + Idle(); + if (_state.IrqSource || _state.NeedNmi) + { Idle(); - if(_state.IrqSource || _state.NeedNmi) { - Idle(); - _state.StopState = CpuStopState::Running; - } - break; + _state.StopState = CpuStopState::Running; + } + break; } //Use the state of the IRQ/NMI flags on the previous cycle to determine if an IRQ is processed or not - if(_state.PrevNeedNmi) { + if (_state.PrevNeedNmi) + { _state.NeedNmi = false; uint32_t originalPc = GetProgramAddress(_state.PC); ProcessInterrupt(_state.EmulationMode ? Sa1Cpu::LegacyNmiVector : Sa1Cpu::NmiVector, true); _console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true); - } else if(_state.PrevIrqSource) { + } + else if (_state.PrevIrqSource) + { uint32_t originalPc = GetProgramAddress(_state.PC); ProcessInterrupt(_state.EmulationMode ? Sa1Cpu::LegacyIrqVector : Sa1Cpu::IrqVector, true); _console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false); @@ -68,10 +74,12 @@ void Sa1Cpu::Idle() void Sa1Cpu::IdleEndJump() { IMemoryHandler* handler = _sa1->GetMemoryMappings()->GetHandler(_state.PC); - if(handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) { + if (handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) + { //Jumps/returns in PRG ROM take an extra cycle _state.CycleCount++; - if(_sa1->GetSnesCpuMemoryType() == SnesMemoryType::PrgRom) { + if (_sa1->GetSnesCpuMemoryType() == SnesMemoryType::PrgRom) + { //Add an extra wait cycle if a conflict occurs at the same time _state.CycleCount++; } @@ -80,9 +88,11 @@ void Sa1Cpu::IdleEndJump() void Sa1Cpu::IdleTakeBranch() { - if(_state.PC & 0x01) { + if (_state.PC & 0x01) + { IMemoryHandler* handler = _sa1->GetMemoryMappings()->GetHandler(_state.PC); - if(handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) { + if (handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) + { //Branches to an odd address take an extra cycle _state.CycleCount++; } @@ -91,23 +101,29 @@ void Sa1Cpu::IdleTakeBranch() bool Sa1Cpu::IsAccessConflict() { - return _sa1->GetSnesCpuMemoryType() == _sa1->GetSa1MemoryType() && _sa1->GetSa1MemoryType() != SnesMemoryType::Register; + return _sa1->GetSnesCpuMemoryType() == _sa1->GetSa1MemoryType() && _sa1->GetSa1MemoryType() != + SnesMemoryType::Register; } void Sa1Cpu::ProcessCpuCycle(uint32_t addr) { _state.CycleCount++; - if(_sa1->GetSa1MemoryType() == SnesMemoryType::SaveRam) { + if (_sa1->GetSa1MemoryType() == SnesMemoryType::SaveRam) + { //BWRAM (save ram) access takes 2 cycles _state.CycleCount++; - if(IsAccessConflict()) { + if (IsAccessConflict()) + { _state.CycleCount += 2; } - } else if(IsAccessConflict()) { + } + else if (IsAccessConflict()) + { //Add a wait cycle when a conflict occurs between both CPUs _state.CycleCount++; - if(_sa1->GetSa1MemoryType() == SnesMemoryType::Sa1InternalRam && _sa1->IsSnesCpuFastRomSpeed()) { + if (_sa1->GetSa1MemoryType() == SnesMemoryType::Sa1InternalRam && _sa1->IsSnesCpuFastRomSpeed()) + { //If it's an IRAM access during FastROM access (speed = 6), add another wait cycle _state.CycleCount++; } @@ -146,42 +162,52 @@ void Sa1Cpu::IncreaseCycleCount(uint64_t cycleCount) void Sa1Cpu::SetReg(CpuRegister reg, uint16_t value) { - switch (reg) { + switch (reg) + { case CpuRegister::CpuRegA: - { - _state.A = value; - } break; + { + _state.A = value; + } + break; case CpuRegister::CpuRegX: - { - _state.X = value; - } break; + { + _state.X = value; + } + break; case CpuRegister::CpuRegY: - { - _state.Y = value; - } break; + { + _state.Y = value; + } + break; case CpuRegister::CpuRegSP: - { - _state.SP = value; - } break; + { + _state.SP = value; + } + break; case CpuRegister::CpuRegD: - { - _state.D = value; - } break; + { + _state.D = value; + } + break; case CpuRegister::CpuRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case CpuRegister::CpuRegK: - { - _state.K = value & 0xFF; - } break; + { + _state.K = value & 0xFF; + } + break; case CpuRegister::CpuRegDBR: - { - _state.DBR = value & 0xFF; - } break; + { + _state.DBR = value & 0xFF; + } + break; case CpuRegister::CpuRegPS: - { - _state.PS = value & 0xFF; - } break; + { + _state.PS = value & 0xFF; + } + break; } } diff --git a/Core/Sa1Cpu.h b/Core/Sa1Cpu.h index d8c6d1c..df32b92 100644 --- a/Core/Sa1Cpu.h +++ b/Core/Sa1Cpu.h @@ -65,8 +65,8 @@ private: void SetSP(uint16_t sp); void SetPS(uint8_t ps); - void SetRegister(uint8_t ®, uint8_t value); - void SetRegister(uint16_t ®, 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); @@ -140,7 +140,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 @@ -168,10 +168,14 @@ private: void EOR(); void ORA(); - template T ShiftLeft(T value); - template T RollLeft(T value); - template T ShiftRight(T value); - template T RollRight(T value); + template + T ShiftLeft(T value); + template + T RollLeft(T value); + template + T ShiftRight(T value); + template + T RollRight(T value); //Shift operations void ASL_Acc(); @@ -207,10 +211,10 @@ private: void PLY(); void PushRegister(uint16_t reg, bool eightBitMode); - void PullRegister(uint16_t ®, bool eightBitMode); + void PullRegister(uint16_t& reg, bool eightBitMode); //Store/load instructions - void LoadRegister(uint16_t ®, bool eightBitMode); + void LoadRegister(uint16_t& reg, bool eightBitMode); void StoreRegister(uint16_t val, bool eightBitMode); void LDA(); @@ -223,7 +227,8 @@ private: void STZ(); //Test bits - template void TestBits(T value, bool alterZeroFlagOnly); + template + void TestBits(T value, bool alterZeroFlagOnly); void BIT(); void TRB(); @@ -311,7 +316,7 @@ private: void RunOp(); public: - Sa1Cpu(Sa1 *sa1, Console* console); + Sa1Cpu(Sa1* sa1, Console* console); virtual ~Sa1Cpu(); void PowerOn(); @@ -322,7 +327,7 @@ public: CpuState GetState(); uint64_t GetCycleCount(); - template + template void IncreaseCycleCount(); void SetNmiFlag(bool nmiFlag); @@ -333,12 +338,12 @@ public: void IncreaseCycleCount(uint64_t cycleCount); // Inherited via ISerializable - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(CpuRegister reg, uint16_t value); }; -template +template void Sa1Cpu::IncreaseCycleCount() { _state.CycleCount += count; diff --git a/Core/Sa1IRamHandler.h b/Core/Sa1IRamHandler.h index bf7eec8..6da8e15 100644 --- a/Core/Sa1IRamHandler.h +++ b/Core/Sa1IRamHandler.h @@ -6,19 +6,22 @@ class Sa1IRamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; __forceinline uint8_t InternalRead(uint32_t addr) { - if(addr & 0x800) { + if (addr & 0x800) + { return 0; - } else { + } + else + { return _ram[addr & 0x7FF]; } } public: - Sa1IRamHandler(uint8_t *ram) : IMemoryHandler(SnesMemoryType::Sa1InternalRam) + Sa1IRamHandler(uint8_t* ram) : IMemoryHandler(SnesMemoryType::Sa1InternalRam) { _ram = ram; } @@ -33,16 +36,18 @@ public: return InternalRead(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = InternalRead(i); } } void Write(uint32_t addr, uint8_t value) override { - if(!(addr & 0x800)) { + if (!(addr & 0x800)) + { _ram[addr & 0x7FF] = value; } } @@ -50,13 +55,16 @@ public: AddressInfo GetAbsoluteAddress(uint32_t addr) override { AddressInfo info; - if(addr & 0x800) { + if (addr & 0x800) + { info.Address = -1; info.Type = SnesMemoryType::CpuMemory; - } else { + } + else + { info.Address = (addr & 0x7FF); info.Type = _memoryType; } return info; } -}; \ No newline at end of file +}; diff --git a/Core/Sa1Types.h b/Core/Sa1Types.h index b9106f1..34e69bd 100644 --- a/Core/Sa1Types.h +++ b/Core/Sa1Types.h @@ -112,4 +112,4 @@ struct DebugSa1State { CpuState Cpu; Sa1State Sa1; -}; \ No newline at end of file +}; diff --git a/Core/Sa1VectorHandler.h b/Core/Sa1VectorHandler.h index 5422885..d82a449 100644 --- a/Core/Sa1VectorHandler.h +++ b/Core/Sa1VectorHandler.h @@ -7,7 +7,7 @@ class Sa1VectorHandler : public IMemoryHandler { private: - IMemoryHandler * _handler; + IMemoryHandler* _handler; Sa1State* _state; public: @@ -19,19 +19,28 @@ public: uint8_t Read(uint32_t addr) override { - if(addr >= Sa1Cpu::NmiVector && addr <= Sa1Cpu::ResetVector + 1) { + if (addr >= Sa1Cpu::NmiVector && addr <= Sa1Cpu::ResetVector + 1) + { //Override the regular handlers - if(_state->UseCpuNmiVector) { - if(addr == Sa1Cpu::NmiVector) { + if (_state->UseCpuNmiVector) + { + if (addr == Sa1Cpu::NmiVector) + { return (uint8_t)_state->CpuNmiVector; - } else if(addr == Sa1Cpu::NmiVector + 1) { + } + else if (addr == Sa1Cpu::NmiVector + 1) + { return (uint8_t)(_state->CpuNmiVector >> 8); } } - if(_state->UseCpuIrqVector) { - if(addr == Sa1Cpu::IrqVector) { + if (_state->UseCpuIrqVector) + { + if (addr == Sa1Cpu::IrqVector) + { return (uint8_t)_state->CpuIrqVector; - } else if(addr == Sa1Cpu::IrqVector + 1) { + } + else if (addr == Sa1Cpu::IrqVector + 1) + { return (uint8_t)(_state->CpuIrqVector >> 8); } } @@ -45,7 +54,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); } @@ -59,4 +68,4 @@ public: { return _handler->GetAbsoluteAddress(address); } -}; \ No newline at end of file +}; diff --git a/Core/SaveStateManager.cpp b/Core/SaveStateManager.cpp index 84c6c6c..8dd8cc0 100644 --- a/Core/SaveStateManager.cpp +++ b/Core/SaveStateManager.cpp @@ -58,7 +58,7 @@ bool SaveStateManager::LoadState() return LoadState(_lastIndex); } -void SaveStateManager::GetSaveStateHeader(ostream &stream) +void SaveStateManager::GetSaveStateHeader(ostream& stream) { uint32_t emuVersion = _console->GetSettings()->GetVersion(); uint32_t formatVersion = SaveStateManager::FileFormatVersion; @@ -72,9 +72,9 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream) bool isGameboyMode = _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode); stream.write((char*)&isGameboyMode, sizeof(bool)); - #ifndef LIBRETRO +#ifndef LIBRETRO SaveScreenshotData(stream); - #endif +#endif RomInfo romInfo = _console->GetCartridge()->GetRomInfo(); string romName = FolderUtilities::GetFilename(romInfo.RomFile.GetFileName(), true); @@ -83,7 +83,7 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream) stream.write(romName.c_str(), romName.size()); } -void SaveStateManager::SaveState(ostream &stream) +void SaveStateManager::SaveState(ostream& stream) { GetSaveStateHeader(stream); _console->Serialize(stream); @@ -93,14 +93,16 @@ bool SaveStateManager::SaveState(string filepath) { ofstream file(filepath, ios::out | ios::binary); - if(file) { + if (file) + { _console->Lock(); SaveState(file); _console->Unlock(); file.close(); shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->ProcessEvent(EventType::StateSaved); } return true; @@ -111,8 +113,10 @@ bool SaveStateManager::SaveState(string filepath) void SaveStateManager::SaveState(int stateIndex, bool displayMessage) { string filepath = SaveStateManager::GetStateFilepath(stateIndex); - if(SaveState(filepath)) { - if(displayMessage) { + if (SaveState(filepath)) + { + if (displayMessage) + { MessageManager::DisplayMessage("SaveStates", "SaveStateSaved", std::to_string(stateIndex)); } } @@ -127,16 +131,17 @@ void SaveStateManager::SaveScreenshotData(ostream& stream) stream.write((char*)&width, sizeof(uint32_t)); stream.write((char*)&height, sizeof(uint32_t)); - unsigned long compressedSize = compressBound(512*478*2); + unsigned long compressedSize = compressBound(512 * 478 * 2); vector compressedData(compressedSize, 0); - compress2(compressedData.data(), &compressedSize, (const unsigned char*)_console->GetPpu()->GetScreenBuffer(), width*height*2, MZ_DEFAULT_LEVEL); + compress2(compressedData.data(), &compressedSize, (const unsigned char*)_console->GetPpu()->GetScreenBuffer(), + width * height * 2, MZ_DEFAULT_LEVEL); uint32_t screenshotLength = (uint32_t)compressedSize; stream.write((char*)&screenshotLength, sizeof(uint32_t)); stream.write((char*)compressedData.data(), screenshotLength); } -bool SaveStateManager::GetScreenshotData(vector& out, uint32_t &width, uint32_t &height, istream& stream) +bool SaveStateManager::GetScreenshotData(vector& out, uint32_t& width, uint32_t& height, istream& stream) { stream.read((char*)&width, sizeof(uint32_t)); stream.read((char*)&height, sizeof(uint32_t)); @@ -149,67 +154,80 @@ bool SaveStateManager::GetScreenshotData(vector& out, uint32_t &width, out = vector(width * height * 2, 0); unsigned long decompSize = width * height * 2; - if(uncompress(out.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()) == MZ_OK) { + if (uncompress(out.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()) == MZ_OK) + { return true; } return false; } -bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired) +bool SaveStateManager::LoadState(istream& stream, bool hashCheckRequired) { - if(GameClient::Connected()) { + if (GameClient::Connected()) + { MessageManager::DisplayMessage("Netplay", "NetplayNotAllowed"); return false; } char header[3]; stream.read(header, 3); - if(memcmp(header, "MSS", 3) == 0) { + if (memcmp(header, "MSS", 3) == 0) + { uint32_t emuVersion, fileFormatVersion; stream.read((char*)&emuVersion, sizeof(emuVersion)); - if(emuVersion > _console->GetSettings()->GetVersion()) { + if (emuVersion > _console->GetSettings()->GetVersion()) + { MessageManager::DisplayMessage("SaveStates", "SaveStateNewerVersion"); return false; } stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion)); - if(fileFormatVersion <= 5) { + if (fileFormatVersion <= 5) + { MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); return false; - } else { + } + else + { char hash[41] = {}; stream.read(hash, 40); - if(fileFormatVersion >= 8) { + if (fileFormatVersion >= 8) + { bool isGameboyMode = false; stream.read((char*)&isGameboyMode, sizeof(bool)); - if(isGameboyMode != _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) { - MessageManager::DisplayMessage("SaveStates", isGameboyMode ? "SaveStateWrongSystemGb" : "SaveStateWrongSystemSnes"); + if (isGameboyMode != _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) + { + MessageManager::DisplayMessage("SaveStates", + isGameboyMode ? "SaveStateWrongSystemGb" : "SaveStateWrongSystemSnes"); return false; } - } - - if(fileFormatVersion >= 7) { - #ifndef LIBRETRO + } + + if (fileFormatVersion >= 7) + { +#ifndef LIBRETRO vector frameData; uint32_t width = 0; uint32_t height = 0; - if(GetScreenshotData(frameData, width, height, stream)) { + if (GetScreenshotData(frameData, width, height, stream)) + { _console->GetVideoDecoder()->UpdateFrameSync((uint16_t*)frameData.data(), width, height, 0, true); } - #endif +#endif } uint32_t nameLength = 0; stream.read((char*)&nameLength, sizeof(uint32_t)); - + vector nameBuffer(nameLength); stream.read(nameBuffer.data(), nameBuffer.size()); string romName(nameBuffer.data(), nameLength); - + shared_ptr cartridge = _console->GetCartridge(); - if(!cartridge /*|| cartridge->GetSha1Hash() != string(hash)*/) { + if (!cartridge /*|| cartridge->GetSha1Hash() != string(hash)*/) + { //Game isn't loaded, or CRC doesn't match //TODO: Try to find and load the game return false; @@ -233,19 +251,24 @@ bool SaveStateManager::LoadState(string filepath, bool hashCheckRequired) ifstream file(filepath, ios::in | ios::binary); bool result = false; - if(file.good()) { + if (file.good()) + { _console->Lock(); result = LoadState(file, hashCheckRequired); _console->Unlock(); file.close(); - if(result) { + if (result) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->ProcessEvent(EventType::StateLoaded); } } - } else { + } + else + { MessageManager::DisplayMessage("SaveStates", "SaveStateEmpty"); } @@ -255,7 +278,8 @@ bool SaveStateManager::LoadState(string filepath, bool hashCheckRequired) bool SaveStateManager::LoadState(int stateIndex) { string filepath = SaveStateManager::GetStateFilepath(stateIndex); - if(LoadState(filepath, false)) { + if (LoadState(filepath, false)) + { MessageManager::DisplayMessage("SaveStates", "SaveStateLoaded", std::to_string(stateIndex)); return true; } @@ -302,13 +326,18 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame) std::getline(romInfoStream, patchPath); _console->Lock(); - try { - if(_console->LoadRom(romPath, patchPath)) { - if(!resetGame) { + try + { + if (_console->LoadRom(romPath, patchPath)) + { + if (!resetGame) + { SaveStateManager::LoadState(stateStream, false); } } - } catch(std::exception&) { + } + catch (std::exception&) + { _console->Stop(true); } _console->Unlock(); @@ -318,23 +347,27 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png { ifstream stream(saveStatePath, ios::binary); - if(!stream) { + if (!stream) + { return -1; } char header[3]; stream.read(header, 3); - if(memcmp(header, "MSS", 3) == 0) { + if (memcmp(header, "MSS", 3) == 0) + { uint32_t emuVersion = 0; stream.read((char*)&emuVersion, sizeof(emuVersion)); - if(emuVersion > _console->GetSettings()->GetVersion()) { + if (emuVersion > _console->GetSettings()->GetVersion()) + { return -1; } uint32_t fileFormatVersion = 0; stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion)); - if(fileFormatVersion <= 6) { + if (fileFormatVersion <= 6) + { return -1; } @@ -344,11 +377,12 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png vector frameData; uint32_t width = 0; uint32_t height = 0; - if(GetScreenshotData(frameData, width, height, stream)) { + if (GetScreenshotData(frameData, width, height, stream)) + { FrameInfo baseFrameInfo; baseFrameInfo.Width = width; baseFrameInfo.Height = height; - + DefaultVideoFilter filter(_console); filter.SetBaseFrameInfo(baseFrameInfo); FrameInfo frameInfo = filter.GetFrameInfo(); @@ -364,4 +398,4 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png } } return -1; -} \ No newline at end of file +} diff --git a/Core/SaveStateManager.h b/Core/SaveStateManager.h index fcb9f40..9d0a387 100644 --- a/Core/SaveStateManager.h +++ b/Core/SaveStateManager.h @@ -11,7 +11,7 @@ private: atomic _lastIndex; shared_ptr _console; - string GetStateFilepath(int stateIndex); + string GetStateFilepath(int stateIndex); void SaveScreenshotData(ostream& stream); bool GetScreenshotData(vector& out, uint32_t& width, uint32_t& height, istream& stream); @@ -23,12 +23,12 @@ public: void SaveState(); bool LoadState(); - void GetSaveStateHeader(ostream & stream); + void GetSaveStateHeader(ostream& stream); - void SaveState(ostream &stream); + void SaveState(ostream& stream); bool SaveState(string filepath); void SaveState(int stateIndex, bool displayMessage = true); - bool LoadState(istream &stream, bool hashCheckRequired = true); + bool LoadState(istream& stream, bool hashCheckRequired = true); bool LoadState(string filepath, bool hashCheckRequired = true); bool LoadState(int stateIndex); @@ -40,4 +40,4 @@ public: void SelectSaveSlot(int slotIndex); void MoveToNextSlot(); void MoveToPreviousSlot(); -}; \ No newline at end of file +}; diff --git a/Core/SaveStateMessage.h b/Core/SaveStateMessage.h index bc6e4e3..76ef655 100644 --- a/Core/SaveStateMessage.h +++ b/Core/SaveStateMessage.h @@ -11,7 +11,7 @@ class SaveStateMessage : public NetMessage private: vector _activeCheats; vector _stateData; - + ControllerType _controllerTypes[5]; ConsoleRegion _region; uint32_t _ppuExtraScanlinesAfterNmi; @@ -19,7 +19,7 @@ private: uint32_t _gsuClockSpeed; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.StreamVector(_stateData); s.Stream(_region, _ppuExtraScanlinesAfterNmi, _ppuExtraScanlinesBeforeNmi, _gsuClockSpeed); @@ -28,8 +28,10 @@ protected: } public: - SaveStateMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } - + SaveStateMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } + SaveStateMessage(shared_ptr console) : NetMessage(MessageType::SaveState) { //Used when sending state to clients @@ -45,7 +47,8 @@ public: _gsuClockSpeed = emuCfg.GsuClockSpeed; InputConfig inputCfg = console->GetSettings()->GetInputConfig(); - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { _controllerTypes[i] = inputCfg.Controllers[i].Type; } @@ -55,7 +58,7 @@ public: _stateData.resize(dataSize); state.read((char*)_stateData.data(), dataSize); } - + void LoadState(shared_ptr console) { std::stringstream ss; @@ -71,11 +74,12 @@ public: emuCfg.GsuClockSpeed = _gsuClockSpeed; InputConfig inputCfg = console->GetSettings()->GetInputConfig(); - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { inputCfg.Controllers[i].Type = _controllerTypes[i]; } console->GetSettings()->SetEmulationConfig(emuCfg); console->GetSettings()->SetInputConfig(inputCfg); } -}; \ No newline at end of file +}; diff --git a/Core/ScaleFilter.cpp b/Core/ScaleFilter.cpp index 7b19303..90a66e4 100644 --- a/Core/ScaleFilter.cpp +++ b/Core/ScaleFilter.cpp @@ -12,7 +12,8 @@ ScaleFilter::ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale) _scaleFilterType = scaleFilterType; _filterScale = scale; - if(!_hqxInitDone && _scaleFilterType == ScaleFilterType::HQX) { + if (!_hqxInitDone && _scaleFilterType == ScaleFilterType::HQX) + { hqxInit(); _hqxInitDone = true; } @@ -28,60 +29,82 @@ uint32_t ScaleFilter::GetScale() return _filterScale; } -void ScaleFilter::ApplyPrescaleFilter(uint32_t *inputArgbBuffer) +void ScaleFilter::ApplyPrescaleFilter(uint32_t* inputArgbBuffer) { uint32_t* outputBuffer = _outputBuffer; - for(uint32_t y = 0; y < _height; y++) { - for(uint32_t x = 0; x < _width; x++) { - for(uint32_t i = 0; i < _filterScale; i++) { + for (uint32_t y = 0; y < _height; y++) + { + for (uint32_t x = 0; x < _width; x++) + { + for (uint32_t i = 0; i < _filterScale; i++) + { *(outputBuffer++) = *inputArgbBuffer; } inputArgbBuffer++; } - for(uint32_t i = 1; i < _filterScale; i++) { - memcpy(outputBuffer, outputBuffer - _width*_filterScale, _width*_filterScale *4); - outputBuffer += _width*_filterScale; + for (uint32_t i = 1; i < _filterScale; i++) + { + memcpy(outputBuffer, outputBuffer - _width * _filterScale, _width * _filterScale * 4); + outputBuffer += _width * _filterScale; } } } void ScaleFilter::UpdateOutputBuffer(uint32_t width, uint32_t height) { - if(!_outputBuffer || width != _width || height != _height) { + if (!_outputBuffer || width != _width || height != _height) + { delete[] _outputBuffer; _width = width; _height = height; - _outputBuffer = new uint32_t[_width*_height*_filterScale*_filterScale]; + _outputBuffer = new uint32_t[_width * _height * _filterScale * _filterScale]; } } -uint32_t* ScaleFilter::ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity) +uint32_t* ScaleFilter::ApplyFilter(uint32_t* inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity) { UpdateOutputBuffer(width, height); - if(_scaleFilterType == ScaleFilterType::xBRZ) { + if (_scaleFilterType == ScaleFilterType::xBRZ) + { xbrz::scale(_filterScale, inputArgbBuffer, _outputBuffer, width, height, xbrz::ColorFormat::ARGB); - } else if(_scaleFilterType == ScaleFilterType::HQX) { + } + else if (_scaleFilterType == ScaleFilterType::HQX) + { hqx(_filterScale, inputArgbBuffer, _outputBuffer, width, height); - } else if(_scaleFilterType == ScaleFilterType::Scale2x) { - scale(_filterScale, _outputBuffer, width*sizeof(uint32_t)*_filterScale, inputArgbBuffer, width*sizeof(uint32_t), 4, width, height); - } else if(_scaleFilterType == ScaleFilterType::_2xSai) { + } + else if (_scaleFilterType == ScaleFilterType::Scale2x) + { + scale(_filterScale, _outputBuffer, width * sizeof(uint32_t) * _filterScale, inputArgbBuffer, + width * sizeof(uint32_t), 4, width, height); + } + else if (_scaleFilterType == ScaleFilterType::_2xSai) + { twoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::Super2xSai) { + } + else if (_scaleFilterType == ScaleFilterType::Super2xSai) + { supertwoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::SuperEagle) { + } + else if (_scaleFilterType == ScaleFilterType::SuperEagle) + { supereagle_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::Prescale) { + } + else if (_scaleFilterType == ScaleFilterType::Prescale) + { ApplyPrescaleFilter(inputArgbBuffer); } scanlineIntensity = 1.0 - scanlineIntensity; - if(scanlineIntensity < 1.0) { - for(int y = 1, yMax = height * _filterScale; y < yMax; y += 2) { - for(int x = 0, xMax = width * _filterScale; x < xMax; x++) { - uint32_t &color = _outputBuffer[y*xMax + x]; + if (scanlineIntensity < 1.0) + { + for (int y = 1, yMax = height * _filterScale; y < yMax; y += 2) + { + for (int x = 0, xMax = width * _filterScale; x < xMax; x++) + { + uint32_t& color = _outputBuffer[y * xMax + x]; uint8_t r = (color >> 16) & 0xFF, g = (color >> 8) & 0xFF, b = color & 0xFF; r = (uint8_t)(r * scanlineIntensity); g = (uint8_t)(g * scanlineIntensity); @@ -97,32 +120,53 @@ uint32_t* ScaleFilter::ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, ui shared_ptr ScaleFilter::GetScaleFilter(VideoFilterType filter) { shared_ptr scaleFilter; - switch(filter) { - case VideoFilterType::NTSC: - case VideoFilterType::None: - break; + switch (filter) + { + case VideoFilterType::NTSC: + case VideoFilterType::None: + break; - case VideoFilterType::xBRZ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); break; - case VideoFilterType::xBRZ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); break; - case VideoFilterType::xBRZ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); break; - case VideoFilterType::xBRZ5x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); break; - case VideoFilterType::xBRZ6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); break; - case VideoFilterType::HQ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); break; - case VideoFilterType::HQ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); break; - case VideoFilterType::HQ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); break; - case VideoFilterType::Scale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); break; - case VideoFilterType::Scale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); break; - case VideoFilterType::Scale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); break; - case VideoFilterType::_2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); break; - case VideoFilterType::Super2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); break; - case VideoFilterType::SuperEagle: scaleFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); break; + case VideoFilterType::xBRZ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); + break; + case VideoFilterType::xBRZ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); + break; + case VideoFilterType::xBRZ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); + break; + case VideoFilterType::xBRZ5x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); + break; + case VideoFilterType::xBRZ6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); + break; + case VideoFilterType::HQ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); + break; + case VideoFilterType::HQ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); + break; + case VideoFilterType::HQ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); + break; + case VideoFilterType::Scale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); + break; + case VideoFilterType::Scale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); + break; + case VideoFilterType::Scale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); + break; + case VideoFilterType::_2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); + break; + case VideoFilterType::Super2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); + break; + case VideoFilterType::SuperEagle: scaleFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); + break; - case VideoFilterType::Prescale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 2)); break; - case VideoFilterType::Prescale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 3)); break; - case VideoFilterType::Prescale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 4)); break; - case VideoFilterType::Prescale6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 6)); break; - case VideoFilterType::Prescale8x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 8)); break; - case VideoFilterType::Prescale10x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 10)); break; + case VideoFilterType::Prescale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 2)); + break; + case VideoFilterType::Prescale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 3)); + break; + case VideoFilterType::Prescale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 4)); + break; + case VideoFilterType::Prescale6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 6)); + break; + case VideoFilterType::Prescale8x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 8)); + break; + case VideoFilterType::Prescale10x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 10)); + break; } return scaleFilter; } @@ -133,4 +177,4 @@ FrameInfo ScaleFilter::GetFrameInfo(FrameInfo baseFrameInfo) info.Height *= this->GetScale(); info.Width *= this->GetScale(); return info; -} \ No newline at end of file +} diff --git a/Core/ScaleFilter.h b/Core/ScaleFilter.h index d53de67..a102234 100644 --- a/Core/ScaleFilter.h +++ b/Core/ScaleFilter.h @@ -9,11 +9,11 @@ private: static bool _hqxInitDone; uint32_t _filterScale; ScaleFilterType _scaleFilterType; - uint32_t *_outputBuffer = nullptr; + uint32_t* _outputBuffer = nullptr; uint32_t _width = 0; uint32_t _height = 0; - void ApplyPrescaleFilter(uint32_t *inputArgbBuffer); + void ApplyPrescaleFilter(uint32_t* inputArgbBuffer); void UpdateOutputBuffer(uint32_t width, uint32_t height); public: @@ -21,8 +21,8 @@ public: ~ScaleFilter(); uint32_t GetScale(); - uint32_t* ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity); + uint32_t* ApplyFilter(uint32_t* inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity); FrameInfo GetFrameInfo(FrameInfo baseFrameInfo); static shared_ptr GetScaleFilter(VideoFilterType filter); -}; \ No newline at end of file +}; diff --git a/Core/ScriptHost.cpp b/Core/ScriptHost.cpp index 4e9e3c9..7d551b4 100644 --- a/Core/ScriptHost.cpp +++ b/Core/ScriptHost.cpp @@ -26,7 +26,8 @@ bool ScriptHost::LoadScript(string scriptName, string scriptContent, Debugger* d { #ifndef LIBRETRO _context.reset(new LuaScriptingContext(debugger)); - if(!_context->LoadScript(scriptName, scriptContent, debugger)) { + if (!_context->LoadScript(scriptName, scriptContent, debugger)) + { return false; } return true; @@ -35,28 +36,35 @@ bool ScriptHost::LoadScript(string scriptName, string scriptContent, Debugger* d #endif } -void ScriptHost::ProcessMemoryOperation(uint32_t addr, uint8_t &value, MemoryOperationType type, CpuType cpuType) +void ScriptHost::ProcessMemoryOperation(uint32_t addr, uint8_t& value, MemoryOperationType type, CpuType cpuType) { - if(_context) { - switch(type) { - case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::CpuRead, cpuType); break; - case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::CpuWrite, cpuType); break; - case MemoryOperationType::ExecOpCode: _context->CallMemoryCallback(addr, value, CallbackType::CpuExec, cpuType); break; - default: break; + if (_context) + { + switch (type) + { + case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::CpuRead, cpuType); + break; + case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::CpuWrite, cpuType); + break; + case MemoryOperationType::ExecOpCode: _context->CallMemoryCallback(addr, value, CallbackType::CpuExec, cpuType); + break; + default: break; } } } void ScriptHost::ProcessEvent(EventType eventType) { - if(_context) { + if (_context) + { _context->CallEventCallback(eventType); } } bool ScriptHost::ProcessSavestate() { - if(_context) { + if (_context) + { return _context->ProcessSavestate(); } return false; @@ -64,7 +72,8 @@ bool ScriptHost::ProcessSavestate() bool ScriptHost::CheckStateLoadedFlag() { - if(_context) { + if (_context) + { return _context->CheckStateLoadedFlag(); } return false; diff --git a/Core/ScriptHost.h b/Core/ScriptHost.h index ce52c89..2b96c74 100644 --- a/Core/ScriptHost.h +++ b/Core/ScriptHost.h @@ -20,9 +20,9 @@ public: bool LoadScript(string scriptName, string scriptContent, Debugger* debugger); - void ProcessMemoryOperation(uint32_t addr, uint8_t &value, MemoryOperationType type, CpuType cpuType); + void ProcessMemoryOperation(uint32_t addr, uint8_t& value, MemoryOperationType type, CpuType cpuType); void ProcessEvent(EventType eventType); bool ProcessSavestate(); bool CheckStateLoadedFlag(); -}; \ No newline at end of file +}; diff --git a/Core/ScriptManager.cpp b/Core/ScriptManager.cpp index c330d9c..099108e 100644 --- a/Core/ScriptManager.cpp +++ b/Core/ScriptManager.cpp @@ -19,17 +19,22 @@ int ScriptManager::LoadScript(string name, string content, int32_t scriptId) DebugBreakHelper helper(_debugger); auto lock = _scriptLock.AcquireSafe(); - if(scriptId < 0) { + if (scriptId < 0) + { shared_ptr script(new ScriptHost(_nextScriptId++)); script->LoadScript(name, content, _debugger); _scripts.push_back(script); _hasScript = true; return script->GetScriptId(); - } else { - auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr &script) { + } + else + { + auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr& script) + { return script->GetScriptId() == scriptId; }); - if(result != _scripts.end()) { + if (result != _scripts.end()) + { //Send a ScriptEnded event before reloading the code (*result)->ProcessEvent(EventType::ScriptEnded); @@ -45,8 +50,10 @@ void ScriptManager::RemoveScript(int32_t scriptId) { DebugBreakHelper helper(_debugger); auto lock = _scriptLock.AcquireSafe(); - _scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr& script) { - if(script->GetScriptId() == scriptId) { + _scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr& script) + { + if (script->GetScriptId() == scriptId) + { //Send a ScriptEnded event before unloading the script script->ProcessEvent(EventType::ScriptEnded); _debugger->GetConsole()->GetDebugHud()->ClearScreen(); @@ -60,8 +67,10 @@ void ScriptManager::RemoveScript(int32_t scriptId) const char* ScriptManager::GetScriptLog(int32_t scriptId) { auto lock = _scriptLock.AcquireSafe(); - for(shared_ptr &script : _scripts) { - if(script->GetScriptId() == scriptId) { + for (shared_ptr& script : _scripts) + { + if (script->GetScriptId() == scriptId) + { return script->GetLog(); } } @@ -70,17 +79,21 @@ const char* ScriptManager::GetScriptLog(int32_t scriptId) void ScriptManager::ProcessEvent(EventType type) { - if(_hasScript) { - for(shared_ptr &script : _scripts) { + if (_hasScript) + { + for (shared_ptr& script : _scripts) + { script->ProcessEvent(type); } } } -void ScriptManager::ProcessMemoryOperation(uint32_t address, uint8_t &value, MemoryOperationType type, CpuType cpuType) +void ScriptManager::ProcessMemoryOperation(uint32_t address, uint8_t& value, MemoryOperationType type, CpuType cpuType) { - if(_hasScript) { - for(shared_ptr &script : _scripts) { + if (_hasScript) + { + for (shared_ptr& script : _scripts) + { script->ProcessMemoryOperation(address, value, type, cpuType); } } diff --git a/Core/ScriptManager.h b/Core/ScriptManager.h index 88c24ef..98511f5 100644 --- a/Core/ScriptManager.h +++ b/Core/ScriptManager.h @@ -11,19 +11,19 @@ enum class MemoryOperationType; class ScriptManager { private: - Debugger *_debugger; + Debugger* _debugger; bool _hasScript; SimpleLock _scriptLock; int _nextScriptId; vector> _scripts; public: - ScriptManager(Debugger *debugger); + ScriptManager(Debugger* debugger); __forceinline bool HasScript() { return _hasScript; } int32_t LoadScript(string name, string content, int32_t scriptId); void RemoveScript(int32_t scriptId); const char* GetScriptLog(int32_t scriptId); void ProcessEvent(EventType type); - void ProcessMemoryOperation(uint32_t address, uint8_t &value, MemoryOperationType type, CpuType cpuType); -}; \ No newline at end of file + void ProcessMemoryOperation(uint32_t address, uint8_t& value, MemoryOperationType type, CpuType cpuType); +}; diff --git a/Core/ScriptingContext.cpp b/Core/ScriptingContext.cpp index f8bc5e4..5b818f2 100644 --- a/Core/ScriptingContext.cpp +++ b/Core/ScriptingContext.cpp @@ -8,7 +8,7 @@ string ScriptingContext::_log = ""; -ScriptingContext::ScriptingContext(Debugger *debugger) +ScriptingContext::ScriptingContext(Debugger* debugger) { _debugger = debugger; } @@ -17,7 +17,8 @@ void ScriptingContext::Log(string message) { auto lock = _logLock.AcquireSafe(); _logRows.push_back(message); - if(_logRows.size() > 500) { + if (_logRows.size() > 500) + { _logRows.pop_front(); } } @@ -26,7 +27,8 @@ const char* ScriptingContext::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string &msg : _logRows) { + for (string& msg : _logRows) + { ss << msg << "\n"; } _log = ss.str(); @@ -43,7 +45,7 @@ string ScriptingContext::GetScriptName() return _scriptName; } -void ScriptingContext::CallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) +void ScriptingContext::CallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) { _inExecOpEvent = type == CallbackType::CpuExec; InternalCallMemoryCallback(addr, value, type, cpuType); @@ -81,13 +83,16 @@ bool ScriptingContext::CheckStateLoadedFlag() return stateLoaded; } -void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { - if(endAddr < startAddr) { + if (endAddr < startAddr) + { return; } - if(startAddr == 0 && endAddr == 0) { + if (startAddr == 0 && endAddr == 0) + { endAddr = 0xFFFFFF; } @@ -99,19 +104,25 @@ void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, _callbacks[(int)type].push_back(callback); } -void ScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void ScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { - if(endAddr < startAddr) { + if (endAddr < startAddr) + { return; } - if(startAddr == 0 && endAddr == 0) { + if (startAddr == 0 && endAddr == 0) + { endAddr = 0xFFFFFF; } - for(size_t i = 0; i < _callbacks[(int)type].size(); i++) { - MemoryCallback &callback = _callbacks[(int)type][i]; - if(callback.Reference == reference && callback.Type == cpuType && (int)callback.StartAddress == startAddr && (int)callback.EndAddress == endAddr) { + for (size_t i = 0; i < _callbacks[(int)type].size(); i++) + { + MemoryCallback& callback = _callbacks[(int)type][i]; + if (callback.Reference == reference && callback.Type == cpuType && (int)callback.StartAddress == startAddr && (int + )callback.EndAddress == endAddr) + { _callbacks[(int)type].erase(_callbacks[(int)type].begin() + i); break; } @@ -125,27 +136,34 @@ void ScriptingContext::RegisterEventCallback(EventType type, int reference) void ScriptingContext::UnregisterEventCallback(EventType type, int reference) { - vector &callbacks = _eventCallbacks[(int)type]; + vector& callbacks = _eventCallbacks[(int)type]; callbacks.erase(std::remove(callbacks.begin(), callbacks.end(), reference), callbacks.end()); } void ScriptingContext::RequestSaveState(int slot) { _saveSlot = slot; - if(_inExecOpEvent) { + if (_inExecOpEvent) + { SaveState(); - } else { + } + else + { _saveSlotData.erase(slot); } } bool ScriptingContext::RequestLoadState(int slot) { - if(_saveSlotData.find(slot) != _saveSlotData.end()) { + if (_saveSlotData.find(slot) != _saveSlotData.end()) + { _loadSlot = slot; - if(_inExecOpEvent) { + if (_inExecOpEvent) + { return LoadState(); - } else { + } + else + { return true; } } @@ -154,7 +172,8 @@ bool ScriptingContext::RequestLoadState(int slot) void ScriptingContext::SaveState() { - if(_saveSlot >= 0) { + if (_saveSlot >= 0) + { stringstream ss; _debugger->GetConsole()->GetSaveStateManager()->SaveState(ss); _saveSlotData[_saveSlot] = ss.str(); @@ -164,12 +183,14 @@ void ScriptingContext::SaveState() bool ScriptingContext::LoadState() { - if(_loadSlot >= 0 && _saveSlotData.find(_loadSlot) != _saveSlotData.end()) { + if (_loadSlot >= 0 && _saveSlotData.find(_loadSlot) != _saveSlotData.end()) + { stringstream ss; ss << _saveSlotData[_loadSlot]; bool result = _debugger->GetConsole()->GetSaveStateManager()->LoadState(ss); _loadSlot = -1; - if(result) { + if (result) + { _stateLoaded = true; } return result; @@ -182,7 +203,8 @@ bool ScriptingContext::LoadState(string stateData) stringstream ss; ss << stateData; bool result = _debugger->GetConsole()->GetSaveStateManager()->LoadState(ss); - if(result) { + if (result) + { _stateLoaded = true; } return result; @@ -196,9 +218,11 @@ bool ScriptingContext::ProcessSavestate() string ScriptingContext::GetSavestateData(int slot) { - if(slot >= 0) { + if (slot >= 0) + { auto result = _saveSlotData.find(slot); - if(result != _saveSlotData.end()) { + if (result != _saveSlotData.end()) + { return result->second; } } @@ -208,7 +232,8 @@ string ScriptingContext::GetSavestateData(int slot) void ScriptingContext::ClearSavestateData(int slot) { - if(slot >= 0) { + if (slot >= 0) + { _saveSlotData.erase(slot); } -} \ No newline at end of file +} diff --git a/Core/ScriptingContext.h b/Core/ScriptingContext.h index 934dda9..7da9ae0 100644 --- a/Core/ScriptingContext.h +++ b/Core/ScriptingContext.h @@ -48,12 +48,16 @@ protected: vector _callbacks[3]; vector _eventCallbacks[(int)EventType::EventTypeSize]; - virtual void InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) = 0; + virtual void InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) = 0; virtual int InternalCallEventCallback(EventType type) = 0; public: ScriptingContext(Debugger* debugger); - virtual ~ScriptingContext() {} + + virtual ~ScriptingContext() + { + } + virtual bool LoadScript(string scriptName, string scriptContent, Debugger* debugger) = 0; void Log(string message); @@ -71,13 +75,13 @@ public: void ClearSavestateData(int slot); bool ProcessSavestate(); - void CallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType); + void CallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType); int CallEventCallback(EventType type); bool CheckInitDone(); bool CheckInStartFrameEvent(); bool CheckInExecOpEvent(); bool CheckStateLoadedFlag(); - + void RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference); virtual void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference); void RegisterEventCallback(EventType type, int reference); diff --git a/Core/Sdd1.cpp b/Core/Sdd1.cpp index 3b15aec..03fb12c 100644 --- a/Core/Sdd1.cpp +++ b/Core/Sdd1.cpp @@ -10,10 +10,10 @@ Sdd1::Sdd1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) { //This handler is used to dynamically map the ROM based on the banking registers _sdd1Mmc.reset(new Sdd1Mmc(_state, console->GetCartridge().get())); - - MemoryMappings *cpuMappings = console->GetMemoryManager()->GetMemoryMappings(); - vector> &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); - vector> &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); + + MemoryMappings* cpuMappings = console->GetMemoryManager()->GetMemoryMappings(); + vector>& prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); + vector>& saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); //Regular A Bus register handler, keep a reference to it, it'll be overwritten below _cpuRegisterHandler = cpuMappings->GetHandler(0x4000); @@ -52,41 +52,62 @@ void Sdd1::Reset() uint8_t Sdd1::Read(uint32_t addr) { - if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) { - switch(addr & 0x07) { - case 0: return _state.AllowDmaProcessing; - case 1: return _state.ProcessNextDma; + if ((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) + { + switch (addr & 0x07) + { + case 0: return _state.AllowDmaProcessing; + case 1: return _state.ProcessNextDma; - case 4: case 5: case 6: case 7: - return _state.SelectedBanks[addr & 0x03]; + case 4: + case 5: + case 6: + case 7: + return _state.SelectedBanks[addr & 0x03]; } } - + return _cpuRegisterHandler->Read(addr); } void Sdd1::Write(uint32_t addr, uint8_t value) { - if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) { + if ((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) + { //S-DD1 registers - switch(addr & 0x07) { - case 0: _state.AllowDmaProcessing = value; break; - case 1: _state.ProcessNextDma = value; break; + switch (addr & 0x07) + { + case 0: _state.AllowDmaProcessing = value; + break; + case 1: _state.ProcessNextDma = value; + break; - case 4: case 5: case 6: case 7: - _state.SelectedBanks[addr & 0x03] = value; - break; + case 4: + case 5: + case 6: + case 7: + _state.SelectedBanks[addr & 0x03] = value; + break; } - } else { - if((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) { + } + else + { + if ((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) + { //Keep track of writes to the DMA controller to know which address/length the DMAs will use uint8_t ch = (addr >> 4) & 0x07; - switch(addr & 0x0F) { - case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; break; - case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); break; - case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); break; - case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; break; - case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); break; + switch (addr & 0x0F) + { + case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; + break; + case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); + break; + case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); + break; + case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; + break; + case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); + break; } } @@ -95,7 +116,7 @@ void Sdd1::Write(uint32_t addr, uint8_t value) } } -void Sdd1::Serialize(Serializer &s) +void Sdd1::Serialize(Serializer& s) { s.Stream(_state.AllowDmaProcessing, _state.ProcessNextDma, _state.NeedInit); s.StreamArray(_state.DmaAddress, 8); @@ -116,5 +137,5 @@ void Sdd1::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo Sdd1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } diff --git a/Core/Sdd1.h b/Core/Sdd1.h index b2bc379..c0dea4f 100644 --- a/Core/Sdd1.h +++ b/Core/Sdd1.h @@ -14,13 +14,13 @@ private: IMemoryHandler* _cpuRegisterHandler; public: - Sdd1(Console *console); + Sdd1(Console* console); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; void Reset() override; -}; \ No newline at end of file +}; diff --git a/Core/Sdd1Decomp.cpp b/Core/Sdd1Decomp.cpp index d171cbb..682f593 100644 --- a/Core/Sdd1Decomp.cpp +++ b/Core/Sdd1Decomp.cpp @@ -33,7 +33,7 @@ understood. #include "Sdd1Decomp.h" #include "Sdd1Mmc.h" -void SDD1_IM::prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr) +void SDD1_IM::prepareDecomp(Sdd1Mmc* mmc, uint32_t readAddr) { _sdd1Mmc = mmc; _readAddr = readAddr; @@ -51,12 +51,14 @@ uint8_t SDD1_IM::getCodeword(uint8_t code_len) ++bit_count; - if(codeword & 0x80) { + if (codeword & 0x80) + { codeword |= _sdd1Mmc->ReadRom(_readAddr + 1) >> (9 - bit_count); bit_count += code_len; } - if(bit_count & 0x08) { + if (bit_count & 0x08) + { _readAddr++; bit_count &= 0x07; } @@ -64,12 +66,12 @@ uint8_t SDD1_IM::getCodeword(uint8_t code_len) return codeword; } -void SDD1_IM::Serialize(Serializer &s) +void SDD1_IM::Serialize(Serializer& s) { s.Stream(_readAddr, bit_count); } -SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) : +SDD1_GCD::SDD1_GCD(SDD1_IM* associatedIM) : IM(associatedIM) { } @@ -77,61 +79,61 @@ SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) : ////////////////////////////////////////////////////// -void SDD1_GCD::getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind) +void SDD1_GCD::getRunCount(uint8_t code_num, uint8_t* MPScount, bool* LPSind) { - const uint8_t run_count[] = { - 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, - 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, - 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, - 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, - 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, - 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, - 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, - 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, - 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, - 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, - 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, - 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, - 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, - 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, - 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, - 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, - 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, - 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, - 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, - 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, - 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, - 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, - 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, - 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, - 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, - 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, - 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, - 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, - 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, - 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, - 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, - 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, + 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, + 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, + 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, + 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, + 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, + 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, + 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, + 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, + 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, + 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, + 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, + 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, + 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, + 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, + 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, + 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, + 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, + 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, + 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, + 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, + 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, + 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, + 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, + 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, + 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, + 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, + 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, + 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, + 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, }; uint8_t codeword = IM->getCodeword(code_num); - if(codeword & 0x80) { + if (codeword & 0x80) + { *LPSind = 1; *MPScount = run_count[codeword >> (code_num ^ 0x07)]; - } else { + } + else + { *MPScount = (1 << code_num); } - } /////////////////////////////////////////////////////// -SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code) : +SDD1_BG::SDD1_BG(SDD1_GCD* associatedGCD, uint8_t code) : code_num(code), GCD(associatedGCD) { - } /////////////////////////////////////////////// @@ -139,38 +141,37 @@ SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code) : void SDD1_BG::prepareDecomp(void) { - MPScount = 0; LPSind = 0; - } ////////////////////////////////////////////// -uint8_t SDD1_BG::getBit(bool *endOfRun) +uint8_t SDD1_BG::getBit(bool* endOfRun) { - uint8_t bit; - if(!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind); + if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind); - if(MPScount) { + if (MPScount) + { bit = 0; MPScount--; - } else { + } + else + { bit = 1; LPSind = 0; } - if(MPScount || LPSind) (*endOfRun) = 0; + if (MPScount || LPSind) (*endOfRun) = 0; else (*endOfRun) = 1; return bit; - } -void SDD1_BG::Serialize(Serializer &s) +void SDD1_BG::Serialize(Serializer& s) { s.Stream(MPScount, LPSind); } @@ -178,12 +179,11 @@ void SDD1_BG::Serialize(Serializer &s) ///////////////////////////////////////////////// -SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, - SDD1_BG *associatedBG2, SDD1_BG *associatedBG3, - SDD1_BG *associatedBG4, SDD1_BG *associatedBG5, - SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) +SDD1_PEM::SDD1_PEM(SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, + SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, + SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, + SDD1_BG* associatedBG6, SDD1_BG* associatedBG7) { - BG[0] = associatedBG0; BG[1] = associatedBG1; BG[2] = associatedBG2; @@ -192,46 +192,45 @@ SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, BG[5] = associatedBG5; BG[6] = associatedBG6; BG[7] = associatedBG7; - } ///////////////////////////////////////////////////////// const SDD1_PEM::state SDD1_PEM::evolution_table[] = { - { 0,25,25}, - { 0, 2, 1}, - { 0, 3, 1}, - { 0, 4, 2}, - { 0, 5, 3}, - { 1, 6, 4}, - { 1, 7, 5}, - { 1, 8, 6}, - { 1, 9, 7}, - { 2,10, 8}, - { 2,11, 9}, - { 2,12,10}, - { 2,13,11}, - { 3,14,12}, - { 3,15,13}, - { 3,16,14}, - { 3,17,15}, - { 4,18,16}, - { 4,19,17}, - { 5,20,18}, - { 5,21,19}, - { 6,22,20}, - { 6,23,21}, - { 7,24,22}, - { 7,24,23}, - { 0,26, 1}, - { 1,27, 2}, - { 2,28, 4}, - { 3,29, 8}, - { 4,30,12}, - { 5,31,16}, - { 6,32,18}, - { 7,24,22} + {0, 25, 25}, + {0, 2, 1}, + {0, 3, 1}, + {0, 4, 2}, + {0, 5, 3}, + {1, 6, 4}, + {1, 7, 5}, + {1, 8, 6}, + {1, 9, 7}, + {2, 10, 8}, + {2, 11, 9}, + {2, 12, 10}, + {2, 13, 11}, + {3, 14, 12}, + {3, 15, 13}, + {3, 16, 14}, + {3, 17, 15}, + {4, 18, 16}, + {4, 19, 17}, + {5, 20, 18}, + {5, 21, 19}, + {6, 22, 20}, + {6, 23, 21}, + {7, 24, 22}, + {7, 24, 23}, + {0, 26, 1}, + {1, 27, 2}, + {2, 28, 4}, + {3, 29, 8}, + {4, 30, 12}, + {5, 31, 16}, + {6, 32, 18}, + {7, 24, 22} }; ////////////////////////////////////////////////////// @@ -239,12 +238,11 @@ const SDD1_PEM::state SDD1_PEM::evolution_table[] = { void SDD1_PEM::prepareDecomp(void) { - - for(uint8_t i = 0; i < 32; i++) { + for (uint8_t i = 0; i < 32; i++) + { contextInfo[i].status = 0; contextInfo[i].MPS = 0; } - } ///////////////////////////////////////////////////////// @@ -255,18 +253,22 @@ uint8_t SDD1_PEM::getBit(uint8_t context) bool endOfRun; uint8_t bit; - SDD1_ContextInfo *pContInfo = &contextInfo[context]; + SDD1_ContextInfo* pContInfo = &contextInfo[context]; uint8_t currStatus = pContInfo->status; - const state *pState = &SDD1_PEM::evolution_table[currStatus]; + const state* pState = &SDD1_PEM::evolution_table[currStatus]; uint8_t currentMPS = pContInfo->MPS; bit = (BG[pState->code_num])->getBit(&endOfRun); - if(endOfRun) { - if(bit) { - if(!(currStatus & 0xfe)) (pContInfo->MPS) ^= 0x01; + if (endOfRun) + { + if (bit) + { + if (!(currStatus & 0xfe)) (pContInfo->MPS) ^= 0x01; (pContInfo->status) = pState->nextIfLPS; - } else { + } + else + { (pContInfo->status) = pState->nextIfMPS; } } @@ -274,9 +276,10 @@ uint8_t SDD1_PEM::getBit(uint8_t context) return bit ^ currentMPS; } -void SDD1_PEM::Serialize(Serializer &s) +void SDD1_PEM::Serialize(Serializer& s) { - for(int i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) + { s.Stream(contextInfo[i].status, contextInfo[i].MPS); } } @@ -284,10 +287,9 @@ void SDD1_PEM::Serialize(Serializer &s) ////////////////////////////////////////////////////////////// -SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) : +SDD1_CM::SDD1_CM(SDD1_PEM* associatedPEM) : PEM(associatedPEM) { - } ////////////////////////////////////////////////////////////// @@ -298,16 +300,17 @@ void SDD1_CM::prepareDecomp(uint8_t firstByte) bitplanesInfo = firstByte & 0xc0; contextBitsInfo = firstByte & 0x30; bit_number = 0; - for(int i = 0; i < 8; i++) prevBitplaneBits[i] = 0; - switch(bitplanesInfo) { - case 0x00: - currBitplane = 1; - break; - case 0x40: - currBitplane = 7; - break; - case 0x80: - currBitplane = 3; + for (int i = 0; i < 8; i++) prevBitplaneBits[i] = 0; + switch (bitplanesInfo) + { + case 0x00: + currBitplane = 1; + break; + case 0x40: + currBitplane = 7; + break; + case 0x80: + currBitplane = 3; } } @@ -316,41 +319,42 @@ void SDD1_CM::prepareDecomp(uint8_t firstByte) uint8_t SDD1_CM::getBit(void) { - uint8_t currContext; - uint16_t *context_bits; + uint16_t* context_bits; - switch(bitplanesInfo) { - case 0x00: - currBitplane ^= 0x01; - break; - case 0x40: - currBitplane ^= 0x01; - if(!(bit_number & 0x7f)) currBitplane = ((currBitplane + 2) & 0x07); - break; - case 0x80: - currBitplane ^= 0x01; - if(!(bit_number & 0x7f)) currBitplane ^= 0x02; - break; - case 0xc0: - currBitplane = bit_number & 0x07; + switch (bitplanesInfo) + { + case 0x00: + currBitplane ^= 0x01; + break; + case 0x40: + currBitplane ^= 0x01; + if (!(bit_number & 0x7f)) currBitplane = ((currBitplane + 2) & 0x07); + break; + case 0x80: + currBitplane ^= 0x01; + if (!(bit_number & 0x7f)) currBitplane ^= 0x02; + break; + case 0xc0: + currBitplane = bit_number & 0x07; } context_bits = &prevBitplaneBits[currBitplane]; currContext = (currBitplane & 0x01) << 4; - switch(contextBitsInfo) { - case 0x00: - currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); - break; - case 0x10: - currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); - break; - case 0x20: - currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); - break; - case 0x30: - currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); + switch (contextBitsInfo) + { + case 0x00: + currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x10: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); + break; + case 0x20: + currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x30: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); } uint8_t bit = PEM->getBit(currContext); @@ -361,10 +365,9 @@ uint8_t SDD1_CM::getBit(void) bit_number++; return bit; - } -void SDD1_CM::Serialize(Serializer &s) +void SDD1_CM::Serialize(Serializer& s) { s.Stream(bitplanesInfo, contextBitsInfo, bit_number, currBitplane); s.StreamArray(prevBitplaneBits, 8); @@ -373,10 +376,9 @@ void SDD1_CM::Serialize(Serializer &s) ////////////////////////////////////////////////// -SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) : +SDD1_OL::SDD1_OL(SDD1_CM* associatedCM) : CM(associatedCM) { - } /////////////////////////////////////////////////// @@ -393,55 +395,64 @@ void SDD1_OL::prepareDecomp(uint8_t firstByte) uint8_t SDD1_OL::decompressByte() { - switch(bitplanesInfo) { - case 0x00: - case 0x40: - case 0x80: - if(_regs[0] == 0) { - _regs[0] = ~_regs[0]; - return _regs[2]; - } else { - _regs[1] = 0; - _regs[2] = 0; - _regs[0] = 0x80; - - while(_regs[0]) { - if(CM->getBit()) { - _regs[1] |= _regs[0]; - } - - if(CM->getBit()) { - _regs[2] |= _regs[0]; - } - - _regs[0] >>= 1; - } - return _regs[1]; - } - break; - - case 0xC0: + switch (bitplanesInfo) + { + case 0x00: + case 0x40: + case 0x80: + if (_regs[0] == 0) + { + _regs[0] = ~_regs[0]; + return _regs[2]; + } + else + { _regs[1] = 0; - _regs[0] = 0x01; - while(_regs[0]) { - if(CM->getBit()) { + _regs[2] = 0; + _regs[0] = 0x80; + + while (_regs[0]) + { + if (CM->getBit()) + { _regs[1] |= _regs[0]; } - _regs[0] <<= 1; + + if (CM->getBit()) + { + _regs[2] |= _regs[0]; + } + + _regs[0] >>= 1; } return _regs[1]; + } + break; + + case 0xC0: + _regs[1] = 0; + _regs[0] = 0x01; + while (_regs[0]) + { + if (CM->getBit()) + { + _regs[1] |= _regs[0]; + } + _regs[0] <<= 1; + } + return _regs[1]; } throw std::runtime_error("SDD1_OL::decompressByte: Unexpected value"); } -void SDD1_OL::Serialize(Serializer &s) +void SDD1_OL::Serialize(Serializer& s) { s.Stream(bitplanesInfo); s.StreamArray(_regs, 3); } -void Sdd1Decomp::Init(Sdd1Mmc *mmc, uint32_t readAddr) +void Sdd1Decomp::Init(Sdd1Mmc* mmc, uint32_t readAddr) { uint8_t firstByte = mmc->ReadRom(readAddr); IM.prepareDecomp(mmc, readAddr); @@ -463,7 +474,7 @@ uint8_t Sdd1Decomp::GetDecompressedByte() return OL.decompressByte(); } -void Sdd1Decomp::Serialize(Serializer &s) +void Sdd1Decomp::Serialize(Serializer& s) { s.Stream(&IM); s.Stream(&BG0); @@ -487,5 +498,4 @@ Sdd1Decomp::Sdd1Decomp() : CM(&PEM), OL(&CM) { - } diff --git a/Core/Sdd1Decomp.h b/Core/Sdd1Decomp.h index e927326..fd2b850 100644 --- a/Core/Sdd1Decomp.h +++ b/Core/Sdd1Decomp.h @@ -35,14 +35,18 @@ understood. class Sdd1Mmc; class SDD1_IM : public ISerializable -{ //Input Manager +{ + //Input Manager Sdd1Mmc* _sdd1Mmc; public: - SDD1_IM(void) {} - void prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr); + SDD1_IM(void) + { + } + + void prepareDecomp(Sdd1Mmc* mmc, uint32_t readAddr); uint8_t getCodeword(const uint8_t code_len); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; private: uint32_t _readAddr; @@ -53,53 +57,54 @@ private: class SDD1_GCD -{ //Golomb-Code Decoder +{ + //Golomb-Code Decoder public: - SDD1_GCD(SDD1_IM *associatedIM); - void getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind); - -private: - SDD1_IM * const IM; + SDD1_GCD(SDD1_IM* associatedIM); + void getRunCount(uint8_t code_num, uint8_t* MPScount, bool* LPSind); +private: + SDD1_IM* const IM; }; ////////////////////////////////////////////////////// class SDD1_BG : public ISerializable -{ // Bits Generator +{ + // Bits Generator public: - SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code); + SDD1_BG(SDD1_GCD* associatedGCD, uint8_t code); void prepareDecomp(void); - uint8_t getBit(bool *endOfRun); - - void Serialize(Serializer &s) override; + uint8_t getBit(bool* endOfRun); + + void Serialize(Serializer& s) override; private: const uint8_t code_num; uint8_t MPScount; bool LPSind; - SDD1_GCD *const GCD; - + SDD1_GCD* const GCD; }; //////////////////////////////////////////////// class SDD1_PEM : public ISerializable -{ //Probability Estimation Module +{ + //Probability Estimation Module public: - SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, - SDD1_BG *associatedBG2, SDD1_BG *associatedBG3, - SDD1_BG *associatedBG4, SDD1_BG *associatedBG5, - SDD1_BG *associatedBG6, SDD1_BG *associatedBG7); + SDD1_PEM(SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, + SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, + SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, + SDD1_BG* associatedBG6, SDD1_BG* associatedBG7); void prepareDecomp(void); uint8_t getBit(uint8_t context); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: struct state @@ -108,28 +113,31 @@ private: uint8_t nextIfMPS; uint8_t nextIfLPS; }; + static const state evolution_table[]; + struct SDD1_ContextInfo { uint8_t status; uint8_t MPS; } contextInfo[32]; - SDD1_BG * BG[8]; + SDD1_BG* BG[8]; }; /////////////////////////////////////////////////// class SDD1_CM : public ISerializable -{ //Context Model +{ + //Context Model public: - SDD1_CM(SDD1_PEM *associatedPEM); + SDD1_CM(SDD1_PEM* associatedPEM); void prepareDecomp(uint8_t firstByte); uint8_t getBit(void); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: uint8_t bitplanesInfo; @@ -137,46 +145,50 @@ private: uint8_t bit_number; uint8_t currBitplane; uint16_t prevBitplaneBits[8]; - SDD1_PEM *const PEM; - + SDD1_PEM* const PEM; }; /////////////////////////////////////////////////// class SDD1_OL : public ISerializable -{ //Output Logic +{ + //Output Logic public: - SDD1_OL(SDD1_CM *associatedCM); + SDD1_OL(SDD1_CM* associatedCM); void prepareDecomp(uint8_t firstByte); uint8_t decompressByte(); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: uint8_t bitplanesInfo; uint8_t _regs[3]; - SDD1_CM *const CM; - + SDD1_CM* const CM; }; class Sdd1Decomp : public ISerializable { public: Sdd1Decomp(); - void Init(Sdd1Mmc *mmc, uint32_t readAddr); + void Init(Sdd1Mmc* mmc, uint32_t readAddr); uint8_t GetDecompressedByte(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; private: SDD1_IM IM; SDD1_GCD GCD; - SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3; - SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7; + SDD1_BG BG0; + SDD1_BG BG1; + SDD1_BG BG2; + SDD1_BG BG3; + SDD1_BG BG4; + SDD1_BG BG5; + SDD1_BG BG6; + SDD1_BG BG7; SDD1_PEM PEM; SDD1_CM CM; SDD1_OL OL; - -}; \ No newline at end of file +}; diff --git a/Core/Sdd1Mmc.cpp b/Core/Sdd1Mmc.cpp index 4427d04..b14661a 100644 --- a/Core/Sdd1Mmc.cpp +++ b/Core/Sdd1Mmc.cpp @@ -3,7 +3,7 @@ #include "Sdd1Types.h" #include "BaseCartridge.h" -Sdd1Mmc::Sdd1Mmc(Sdd1State &state, BaseCartridge *cart) : IMemoryHandler(SnesMemoryType::Register) +Sdd1Mmc::Sdd1Mmc(Sdd1State& state, BaseCartridge* cart) : IMemoryHandler(SnesMemoryType::Register) { _romHandlers = &cart->GetPrgRomHandlers(); _handlerMask = (uint32_t)((*_romHandlers).size() - 1); @@ -19,18 +19,23 @@ IMemoryHandler* Sdd1Mmc::GetHandler(uint32_t addr) { uint8_t bank = (addr >> 20) - 0x0C; uint16_t handlerIndex = ((_state->SelectedBanks[bank] & 0x0F) << 8) | ((addr & 0xFF000) >> 12); - + return (*_romHandlers)[handlerIndex & _handlerMask].get(); } uint8_t Sdd1Mmc::Read(uint32_t addr) { - if(!(addr & 0x400000)) { + if (!(addr & 0x400000)) + { uint16_t handlerIndex; - if(((addr & 0x800000) && _state->SelectedBanks[3] & 0x80) || (!(addr & 0x800000) && (_state->SelectedBanks[1] & 0x80))) { + if (((addr & 0x800000) && _state->SelectedBanks[3] & 0x80) || (!(addr & 0x800000) && (_state->SelectedBanks[1] & + 0x80))) + { //Force mirroring: $20-$3F mirrors $00-$1F, $A0-$BF mirrors $80-$9F handlerIndex = (((addr & 0x1F0000) >> 1) | (addr & 0x7000)) >> 12; - } else { + } + else + { handlerIndex = (((addr & 0x3F0000) >> 1) | (addr & 0x7000)) >> 12; } return (*_romHandlers)[handlerIndex & _handlerMask]->Read(addr); @@ -38,11 +43,15 @@ uint8_t Sdd1Mmc::Read(uint32_t addr) //Banks $C0+ uint8_t activeChannels = _state->ProcessNextDma & _state->AllowDmaProcessing; - if(activeChannels) { + if (activeChannels) + { //Some DMA channels are being processed, need to check if the address being read matches one of the dma channels - for(int i = 0; i < 8; i++) { - if((activeChannels & (1 << i)) && addr == _state->DmaAddress[i]) { - if(_state->NeedInit) { + for (int i = 0; i < 8; i++) + { + if ((activeChannels & (1 << i)) && addr == _state->DmaAddress[i]) + { + if (_state->NeedInit) + { _decompressor.Init(this, addr); _state->NeedInit = false; } @@ -50,7 +59,8 @@ uint8_t Sdd1Mmc::Read(uint32_t addr) uint8_t data = _decompressor.GetDecompressedByte(); _state->DmaLength[i]--; - if(_state->DmaLength[i] == 0) { + if (_state->DmaLength[i] == 0) + { _state->NeedInit = true; _state->ProcessNextDma &= ~(1 << i); } @@ -68,7 +78,7 @@ uint8_t Sdd1Mmc::Peek(uint32_t addr) return 0; } -void Sdd1Mmc::PeekBlock(uint32_t addr, uint8_t *output) +void Sdd1Mmc::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } @@ -83,7 +93,7 @@ AddressInfo Sdd1Mmc::GetAbsoluteAddress(uint32_t address) return GetHandler(address)->GetAbsoluteAddress(address); } -void Sdd1Mmc::Serialize(Serializer &s) +void Sdd1Mmc::Serialize(Serializer& s) { s.Stream(&_decompressor); } diff --git a/Core/Sdd1Mmc.h b/Core/Sdd1Mmc.h index 2b843de..270e6ac 100644 --- a/Core/Sdd1Mmc.h +++ b/Core/Sdd1Mmc.h @@ -11,23 +11,23 @@ class Sdd1Mmc : public IMemoryHandler, public ISerializable { private: Sdd1State* _state; - vector> *_romHandlers; + vector>* _romHandlers; uint32_t _handlerMask; Sdd1Decomp _decompressor; IMemoryHandler* GetHandler(uint32_t addr); public: - Sdd1Mmc(Sdd1State &state, BaseCartridge *cart); + Sdd1Mmc(Sdd1State& state, BaseCartridge* cart); uint8_t ReadRom(uint32_t addr); // Inherited via IMemoryHandler virtual uint8_t Read(uint32_t addr) override; virtual uint8_t Peek(uint32_t addr) override; - virtual void PeekBlock(uint32_t addr, uint8_t * output) override; + virtual void PeekBlock(uint32_t addr, uint8_t* output) override; virtual void Write(uint32_t addr, uint8_t value) override; virtual AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/Sdd1Types.h b/Core/Sdd1Types.h index f474cf0..89f5f68 100644 --- a/Core/Sdd1Types.h +++ b/Core/Sdd1Types.h @@ -10,4 +10,4 @@ struct Sdd1State uint32_t DmaAddress[8]; uint16_t DmaLength[8]; bool NeedInit; -}; \ No newline at end of file +}; diff --git a/Core/SelectControllerMessage.h b/Core/SelectControllerMessage.h index 4e3d6e4..ff3b0b3 100644 --- a/Core/SelectControllerMessage.h +++ b/Core/SelectControllerMessage.h @@ -8,13 +8,15 @@ private: uint8_t _portNumber; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_portNumber); } public: - SelectControllerMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + SelectControllerMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } SelectControllerMessage(uint8_t port) : NetMessage(MessageType::SelectController) { @@ -25,4 +27,4 @@ public: { return _portNumber; } -}; \ No newline at end of file +}; diff --git a/Core/ServerInformationMessage.h b/Core/ServerInformationMessage.h index 97192c6..1fd2bcb 100644 --- a/Core/ServerInformationMessage.h +++ b/Core/ServerInformationMessage.h @@ -8,13 +8,16 @@ private: string _hashSalt; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_hashSalt); } public: - ServerInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {} + ServerInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } + ServerInformationMessage(string hashSalt) : NetMessage(MessageType::ServerInformation) { _hashSalt = hashSalt; diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 9a7ee34..6e44a3f 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -120,7 +120,7 @@ struct AudioConfig uint32_t SampleRate = 48000; uint32_t AudioLatency = 60; - bool EnableCubicInterpolation = true; + bool EnableCubicInterpolation = true; bool MuteSoundInBackground = false; bool ReduceSoundInBackground = true; @@ -186,7 +186,9 @@ struct KeyMapping bool HasKeySet() { - if(A || B || X || Y || L || R || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboX || TurboY || TurboL || TurboR || TurboStart || TurboSelect) { + if (A || B || X || Y || L || R || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboX || + TurboY || TurboL || TurboR || TurboStart || TurboSelect) + { return true; } return false; @@ -195,8 +197,10 @@ struct KeyMapping private: bool HasKeyBinding(uint32_t* buttons, uint32_t count) { - for(uint32_t i = 0; i < count; i++) { - if(buttons[i] != 0) { + for (uint32_t i = 0; i < count; i++) + { + if (buttons[i] != 0) + { return true; } } @@ -215,16 +219,20 @@ struct KeyMappingSet vector GetKeyMappingArray() { vector keyMappings; - if(Mapping1.HasKeySet()) { + if (Mapping1.HasKeySet()) + { keyMappings.push_back(Mapping1); } - if(Mapping2.HasKeySet()) { + if (Mapping2.HasKeySet()) + { keyMappings.push_back(Mapping2); } - if(Mapping3.HasKeySet()) { + if (Mapping3.HasKeySet()) + { keyMappings.push_back(Mapping3); } - if(Mapping4.HasKeySet()) { + if (Mapping4.HasKeySet()) + { keyMappings.push_back(Mapping4); } return keyMappings; @@ -252,7 +260,7 @@ struct InputConfig uint32_t MouseSensitivity = 1; InputDisplayPosition DisplayInputPosition = InputDisplayPosition::TopLeft; - bool DisplayInputPort[5] = { false, false, false, false, false}; + bool DisplayInputPort[5] = {false, false, false, false, false}; bool DisplayInputHorizontally = true; }; @@ -315,9 +323,9 @@ struct GameboyConfig bool BlendFrames = true; bool GbcAdjustColors = true; - uint32_t BgColors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; - uint32_t Obj0Colors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; - uint32_t Obj1Colors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; + uint32_t BgColors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; + uint32_t Obj0Colors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; + uint32_t Obj1Colors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; uint32_t Square1Vol = 100; uint32_t Square2Vol = 100; @@ -423,7 +431,7 @@ enum class EmulatorShortcut ToggleOsd, ToggleAlwaysOnTop, ToggleDebugInfo, - + ToggleAudio, IncreaseVolume, DecreaseVolume, @@ -476,13 +484,16 @@ struct KeyCombination vector GetKeys() { vector result; - if(Key1) { + if (Key1) + { result.push_back(Key1); } - if(Key2) { + if (Key2) + { result.push_back(Key2); } - if(Key3) { + if (Key3) + { result.push_back(Key3); } return result; @@ -493,9 +504,12 @@ struct KeyCombination vector myKeys = GetKeys(); vector otherKeys = keyCombination.GetKeys(); - if(otherKeys.size() > myKeys.size()) { - for(size_t i = 0; i < myKeys.size(); i++) { - if(std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) { + if (otherKeys.size() > myKeys.size()) + { + for (size_t i = 0; i < myKeys.size(); i++) + { + if (std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) + { //Current key combination contains a key not found in the other combination, so it's not a subset return false; } @@ -522,13 +536,13 @@ enum class DebuggerFlags : uint32_t ShowVerifiedData = 0x100, DisassembleVerifiedData = 0x200, - + ShowUnidentifiedData = 0x400, DisassembleUnidentifiedData = 0x800, - + UseAltSpcOpNames = 0x1000, UseLowerCaseDisassembly = 0x2000, - + AutoResetCdl = 0x4000, GbBreakOnInvalidOamAccess = 0x10000, diff --git a/Core/ShortcutKeyHandler.cpp b/Core/ShortcutKeyHandler.cpp index 451ef97..90948b8 100644 --- a/Core/ShortcutKeyHandler.cpp +++ b/Core/ShortcutKeyHandler.cpp @@ -19,8 +19,10 @@ ShortcutKeyHandler::ShortcutKeyHandler(shared_ptr console) _repeatStarted = false; _stopThread = false; - _thread = std::thread([=]() { - while(!_stopThread) { + _thread = std::thread([=]() + { + while (!_stopThread) + { ProcessKeys(); std::this_thread::sleep_for(std::chrono::duration(50)); } @@ -37,8 +39,10 @@ bool ShortcutKeyHandler::IsKeyPressed(EmulatorShortcut shortcut) { KeyCombination keyComb = _console->GetSettings()->GetShortcutKey(shortcut, _keySetIndex); vector supersets = _console->GetSettings()->GetShortcutSupersets(shortcut, _keySetIndex); - for(KeyCombination &superset : supersets) { - if(IsKeyPressed(superset)) { + for (KeyCombination& superset : supersets) + { + if (IsKeyPressed(superset)) + { //A superset is pressed, ignore this subset return false; } @@ -52,7 +56,8 @@ bool ShortcutKeyHandler::IsKeyPressed(KeyCombination comb) { int keyCount = (comb.Key1 ? 1 : 0) + (comb.Key2 ? 1 : 0) + (comb.Key3 ? 1 : 0); - if(keyCount == 0 || _pressedKeys.empty()) { + if (keyCount == 0 || _pressedKeys.empty()) + { return false; } @@ -68,11 +73,13 @@ bool ShortcutKeyHandler::IsKeyPressed(uint32_t keyCode) bool ShortcutKeyHandler::DetectKeyPress(EmulatorShortcut shortcut) { - if(IsKeyPressed(shortcut)) { + if (IsKeyPressed(shortcut)) + { bool newlyPressed = _prevKeysDown[_keySetIndex].find((uint32_t)shortcut) == _prevKeysDown[_keySetIndex].end(); _keysDown[_keySetIndex].emplace((uint32_t)shortcut); - if(newlyPressed && !_isKeyUp) { + if (newlyPressed && !_isKeyUp) + { return true; } } @@ -81,8 +88,10 @@ bool ShortcutKeyHandler::DetectKeyPress(EmulatorShortcut shortcut) bool ShortcutKeyHandler::DetectKeyRelease(EmulatorShortcut shortcut) { - if(!IsKeyPressed(shortcut)) { - if(_prevKeysDown[_keySetIndex].find((uint32_t)shortcut) != _prevKeysDown[_keySetIndex].end()) { + if (!IsKeyPressed(shortcut)) + { + if (_prevKeysDown[_keySetIndex].find((uint32_t)shortcut) != _prevKeysDown[_keySetIndex].end()) + { return true; } } @@ -92,7 +101,8 @@ bool ShortcutKeyHandler::DetectKeyRelease(EmulatorShortcut shortcut) void ShortcutKeyHandler::ProcessRunSingleFrame() { shared_ptr timer = _runSingleFrameRepeatTimer; - if(!timer) { + if (!timer) + { timer.reset(new Timer()); _runSingleFrameRepeatTimer = timer; } @@ -109,80 +119,112 @@ void ShortcutKeyHandler::CheckMappedKeys() bool isMovieRecording = _console->GetMovieManager()->Recording(); //Let the UI handle these shortcuts - for(uint64_t i = (uint64_t)EmulatorShortcut::TakeScreenshot; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) { - if(DetectKeyPress((EmulatorShortcut)i)) { + for (uint64_t i = (uint64_t)EmulatorShortcut::TakeScreenshot; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) + { + if (DetectKeyPress((EmulatorShortcut)i)) + { void* param = (void*)i; _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, param); } } - if(DetectKeyPress(EmulatorShortcut::FastForward)) { + if (DetectKeyPress(EmulatorShortcut::FastForward)) + { settings->SetFlag(EmulationFlags::Turbo); - } else if(DetectKeyRelease(EmulatorShortcut::FastForward)) { + } + else if (DetectKeyRelease(EmulatorShortcut::FastForward)) + { settings->ClearFlag(EmulationFlags::Turbo); } - if(DetectKeyPress(EmulatorShortcut::ToggleFastForward)) { - if(settings->CheckFlag(EmulationFlags::Turbo)) { + if (DetectKeyPress(EmulatorShortcut::ToggleFastForward)) + { + if (settings->CheckFlag(EmulationFlags::Turbo)) + { settings->ClearFlag(EmulationFlags::Turbo); - } else { + } + else + { settings->SetFlag(EmulationFlags::Turbo); } } - for(int i = 0; i < 10; i++) { - if(DetectKeyPress((EmulatorShortcut)((int)EmulatorShortcut::SelectSaveSlot1 + i))) { + for (int i = 0; i < 10; i++) + { + if (DetectKeyPress((EmulatorShortcut)((int)EmulatorShortcut::SelectSaveSlot1 + i))) + { _console->GetSaveStateManager()->SelectSaveSlot(i + 1); } } - if(DetectKeyPress(EmulatorShortcut::MoveToNextStateSlot)) { + if (DetectKeyPress(EmulatorShortcut::MoveToNextStateSlot)) + { _console->GetSaveStateManager()->MoveToNextSlot(); } - if(DetectKeyPress(EmulatorShortcut::MoveToPreviousStateSlot)) { + if (DetectKeyPress(EmulatorShortcut::MoveToPreviousStateSlot)) + { _console->GetSaveStateManager()->MoveToPreviousSlot(); } - if(DetectKeyPress(EmulatorShortcut::SaveState)) { + if (DetectKeyPress(EmulatorShortcut::SaveState)) + { _console->GetSaveStateManager()->SaveState(); } - if(DetectKeyPress(EmulatorShortcut::LoadState)) { + if (DetectKeyPress(EmulatorShortcut::LoadState)) + { _console->GetSaveStateManager()->LoadState(); } - if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) { - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats); + if (DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) + { + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, + (void*)EmulatorShortcut::ToggleCheats); } - if(DetectKeyPress(EmulatorShortcut::RunSingleFrame)) { + if (DetectKeyPress(EmulatorShortcut::RunSingleFrame)) + { ProcessRunSingleFrame(); } - if(DetectKeyRelease(EmulatorShortcut::RunSingleFrame)) { + if (DetectKeyRelease(EmulatorShortcut::RunSingleFrame)) + { _runSingleFrameRepeatTimer.reset(); _repeatStarted = false; } - if(!isNetplayClient && !isMovieRecording) { + if (!isNetplayClient && !isMovieRecording) + { shared_ptr rewindManager = _console->GetRewindManager(); - if(rewindManager) { - if(DetectKeyPress(EmulatorShortcut::ToggleRewind)) { - if(rewindManager->IsRewinding()) { + if (rewindManager) + { + if (DetectKeyPress(EmulatorShortcut::ToggleRewind)) + { + if (rewindManager->IsRewinding()) + { rewindManager->StopRewinding(); - } else { + } + else + { rewindManager->StartRewinding(); } } - if(DetectKeyPress(EmulatorShortcut::Rewind)) { + if (DetectKeyPress(EmulatorShortcut::Rewind)) + { rewindManager->StartRewinding(); - } else if(DetectKeyRelease(EmulatorShortcut::Rewind)) { + } + else if (DetectKeyRelease(EmulatorShortcut::Rewind)) + { rewindManager->StopRewinding(); - } else if(DetectKeyPress(EmulatorShortcut::RewindTenSecs)) { + } + else if (DetectKeyPress(EmulatorShortcut::RewindTenSecs)) + { rewindManager->RewindSeconds(10); - } else if(DetectKeyPress(EmulatorShortcut::RewindOneMin)) { + } + else if (DetectKeyPress(EmulatorShortcut::RewindOneMin)) + { rewindManager->RewindSeconds(60); } } @@ -191,7 +233,8 @@ void ShortcutKeyHandler::CheckMappedKeys() void ShortcutKeyHandler::ProcessKeys() { - if(!_console->GetSettings()->IsInputEnabled()) { + if (!_console->GetSettings()->IsInputEnabled()) + { return; } @@ -202,19 +245,24 @@ void ShortcutKeyHandler::ProcessKeys() _isKeyUp = _pressedKeys.size() < _lastPressedKeys.size(); bool noChange = false; - if(_pressedKeys.size() == _lastPressedKeys.size()) { + if (_pressedKeys.size() == _lastPressedKeys.size()) + { noChange = true; - for(size_t i = 0; i < _pressedKeys.size(); i++) { - if(_pressedKeys[i] != _lastPressedKeys[i]) { + for (size_t i = 0; i < _pressedKeys.size(); i++) + { + if (_pressedKeys[i] != _lastPressedKeys[i]) + { noChange = false; break; } } } - if(!noChange) { + if (!noChange) + { //Only run this if the keys have changed - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { _keysDown[i].clear(); _keySetIndex = i; CheckMappedKeys(); @@ -225,13 +273,15 @@ void ShortcutKeyHandler::ProcessKeys() } shared_ptr timer = _runSingleFrameRepeatTimer; - if(timer) { + if (timer) + { double elapsedMs = timer->GetElapsedMS(); - if((_repeatStarted && elapsedMs >= 50) || (!_repeatStarted && elapsedMs >= 500)) { + if ((_repeatStarted && elapsedMs >= 50) || (!_repeatStarted && elapsedMs >= 500)) + { //Over 500ms has elapsed since the key was first pressed, or over 50ms since repeat mode started (20fps) //In this case, run another frame and pause again. _repeatStarted = true; ProcessRunSingleFrame(); } } -} \ No newline at end of file +} diff --git a/Core/ShortcutKeyHandler.h b/Core/ShortcutKeyHandler.h index 0106199..7efed91 100644 --- a/Core/ShortcutKeyHandler.h +++ b/Core/ShortcutKeyHandler.h @@ -14,7 +14,7 @@ private: thread _thread; atomic _stopThread; SimpleLock _lock; - + int _keySetIndex; vector _pressedKeys; vector _lastPressedKeys; @@ -25,9 +25,9 @@ private: unordered_set _keysDown[2]; unordered_set _prevKeysDown[2]; - + void CheckMappedKeys(); - + bool IsKeyPressed(EmulatorShortcut key); bool IsKeyPressed(KeyCombination comb); bool IsKeyPressed(uint32_t keyCode); @@ -42,4 +42,4 @@ public: ~ShortcutKeyHandler(); void ProcessKeys(); -}; \ No newline at end of file +}; diff --git a/Core/SnesController.cpp b/Core/SnesController.cpp index 12a2b62..e0ba279 100644 --- a/Core/SnesController.cpp +++ b/Core/SnesController.cpp @@ -2,7 +2,8 @@ #include "SnesController.h" #include "Console.h" -SnesController::SnesController(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console, port, keyMappings) +SnesController::SnesController(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice( + console, port, keyMappings) { _turboSpeed = keyMappings.TurboSpeed; } @@ -14,7 +15,8 @@ string SnesController::GetKeyNames() void SnesController::InternalSetStateFromInput() { - for(KeyMapping keyMapping : _keyMappings) { + for (KeyMapping keyMapping : _keyMappings) + { SetPressedState(Buttons::A, keyMapping.A); SetPressedState(Buttons::B, keyMapping.B); SetPressedState(Buttons::X, keyMapping.X); @@ -30,7 +32,8 @@ void SnesController::InternalSetStateFromInput() uint8_t turboFreq = 1 << (4 - _turboSpeed); bool turboOn = (uint8_t)(_console->GetFrameCount() % turboFreq) < turboFreq / 2; - if(turboOn) { + if (turboOn) + { SetPressedState(Buttons::A, keyMapping.TurboA); SetPressedState(Buttons::B, keyMapping.TurboB); SetPressedState(Buttons::X, keyMapping.TurboX); @@ -60,7 +63,7 @@ uint16_t SnesController::ToByte() ((uint8_t)IsPressed(Buttons::R) << 11); } -void SnesController::Serialize(Serializer & s) +void SnesController::Serialize(Serializer& s) { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer); @@ -80,12 +83,16 @@ uint8_t SnesController::ReadRam(uint16_t addr) { uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); - if(_port >= 2) { - output = (_stateBuffer & 0x01) << 1; //P3/P4 are reported in bit 2 - } else { + if (_port >= 2) + { + output = (_stateBuffer & 0x01) << 1; //P3/P4 are reported in bit 2 + } + else + { output = _stateBuffer & 0x01; } _stateBuffer >>= 1; diff --git a/Core/SnesController.h b/Core/SnesController.h index f2572de..3565693 100644 --- a/Core/SnesController.h +++ b/Core/SnesController.h @@ -13,7 +13,7 @@ protected: string GetKeyNames() override; void InternalSetStateFromInput() override; uint16_t ToByte(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void RefreshStateBuffer() override; public: @@ -24,4 +24,4 @@ public: ControllerType GetControllerType() override; uint8_t ReadRam(uint16_t addr) override; void WriteRam(uint16_t addr, uint8_t value) override; -}; \ No newline at end of file +}; diff --git a/Core/SnesMemoryType.h b/Core/SnesMemoryType.h index 80e5f0c..7861f9f 100644 --- a/Core/SnesMemoryType.h +++ b/Core/SnesMemoryType.h @@ -33,4 +33,4 @@ enum class SnesMemoryType GbVideoRam, GbSpriteRam, Register -}; \ No newline at end of file +}; diff --git a/Core/SnesMouse.h b/Core/SnesMouse.h index 608894a..8f85ac9 100644 --- a/Core/SnesMouse.h +++ b/Core/SnesMouse.h @@ -16,7 +16,7 @@ private: protected: bool HasCoordinates() override { return true; } - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer, _sensitivity); @@ -57,14 +57,17 @@ public: uint8_t ReadRam(uint16_t addr) override { uint8_t output = 0; - if((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) { + if ((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) + { StrobeProcessRead(); - if(_strobe) { + if (_strobe) + { _sensitivity = (_sensitivity + 1) % 3; } output = (_stateBuffer & 0x80000000) >> 31; - if(_port >= 2) { + if (_port >= 2) + { output <<= 1; } _stateBuffer <<= 1; @@ -85,10 +88,11 @@ public: dy = std::min(std::abs(dy), 127); uint8_t byte1 = 0; - uint8_t byte2 = 0x01 | ((_sensitivity & 0x03) << 4) | (IsPressed(SnesMouse::Buttons::Left) ? 0x40 : 0) | (IsPressed(SnesMouse::Buttons::Right) ? 0x80 : 0); + uint8_t byte2 = 0x01 | ((_sensitivity & 0x03) << 4) | (IsPressed(SnesMouse::Buttons::Left) ? 0x40 : 0) | ( + IsPressed(SnesMouse::Buttons::Right) ? 0x80 : 0); uint8_t byte3 = dy | upFlag; uint8_t byte4 = dx | leftFlag; _stateBuffer = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } -}; \ No newline at end of file +}; diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index 662ce15..8b68f6a 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -12,7 +12,7 @@ #include "SuperGameboy.h" #include "../Utilities/Equalizer.h" -SoundMixer::SoundMixer(Console *console) +SoundMixer::SoundMixer(Console* console) { _console = console; _audioDevice = nullptr; @@ -25,26 +25,33 @@ SoundMixer::~SoundMixer() delete[] _sampleBuffer; } -void SoundMixer::RegisterAudioDevice(IAudioDevice *audioDevice) +void SoundMixer::RegisterAudioDevice(IAudioDevice* audioDevice) { _audioDevice = audioDevice; } AudioStatistics SoundMixer::GetStatistics() { - if(_audioDevice) { + if (_audioDevice) + { return _audioDevice->GetStatistics(); - } else { + } + else + { return AudioStatistics(); } } void SoundMixer::StopAudio(bool clearBuffer) { - if(_audioDevice) { - if(clearBuffer) { + if (_audioDevice) + { + if (clearBuffer) + { _audioDevice->Stop(); - } else { + } + else + { _audioDevice->Pause(); } } @@ -54,57 +61,73 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_ { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); - if(cfg.EnableEqualizer) { + if (cfg.EnableEqualizer) + { ProcessEqualizer(samples, sampleCount); } uint32_t masterVolume = cfg.MasterVolume; - if(_console->GetSettings()->CheckFlag(EmulationFlags::InBackground)) { - if(cfg.MuteSoundInBackground) { + if (_console->GetSettings()->CheckFlag(EmulationFlags::InBackground)) + { + if (cfg.MuteSoundInBackground) + { masterVolume = 0; - } else if(cfg.ReduceSoundInBackground) { + } + else if (cfg.ReduceSoundInBackground) + { masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100; } - } else if(cfg.ReduceSoundInFastForward && _console->GetSettings()->CheckFlag(EmulationFlags::TurboOrRewind)) { + } + else if (cfg.ReduceSoundInFastForward && _console->GetSettings()->CheckFlag(EmulationFlags::TurboOrRewind)) + { masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100; } _leftSample = samples[0]; _rightSample = samples[1]; - int16_t *out = _sampleBuffer; + int16_t* out = _sampleBuffer; uint32_t count = _resampler->Resample(samples, sampleCount, sourceRate, cfg.SampleRate, out); SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); - if(sgb) { + if (sgb) + { uint32_t targetRate = (uint32_t)(cfg.SampleRate * _resampler->GetRateAdjustment()); sgb->MixAudio(targetRate, out, count); } shared_ptr msu1 = _console->GetMsu1(); - if(msu1) { + if (msu1) + { msu1->MixAudio(out, count, cfg.SampleRate); } - - if(masterVolume < 100) { + + if (masterVolume < 100) + { //Apply volume if not using the default value - for(uint32_t i = 0; i < count * 2; i++) { + for (uint32_t i = 0; i < count * 2; i++) + { out[i] = (int32_t)out[i] * (int32_t)masterVolume / 100; } } shared_ptr rewindManager = _console->GetRewindManager(); - if(!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) { + if (!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) + { bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording(); - if(isRecording) { - if(_waveRecorder) { + if (isRecording) + { + if (_waveRecorder) + { _waveRecorder->WriteSamples(out, count, cfg.SampleRate, true); } _console->GetVideoRenderer()->AddRecordingSound(out, count, cfg.SampleRate); } - if(_audioDevice) { - if(!cfg.EnableAudio) { + if (_audioDevice) + { + if (!cfg.EnableAudio) + { _audioDevice->Stop(); return; } @@ -118,7 +141,8 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_ void SoundMixer::ProcessEqualizer(int16_t* samples, uint32_t sampleCount) { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); - if(!_equalizer) { + if (!_equalizer) + { _equalizer.reset(new Equalizer()); } vector bandGains = { @@ -151,8 +175,8 @@ bool SoundMixer::IsRecording() return _waveRecorder.get() != nullptr; } -void SoundMixer::GetLastSamples(int16_t &left, int16_t &right) +void SoundMixer::GetLastSamples(int16_t& left, int16_t& right) { left = _leftSample; right = _rightSample; -} \ No newline at end of file +} diff --git a/Core/SoundMixer.h b/Core/SoundMixer.h index e8c2e8b..8cedd46 100644 --- a/Core/SoundMixer.h +++ b/Core/SoundMixer.h @@ -7,34 +7,34 @@ class Equalizer; class SoundResampler; class WaveRecorder; -class SoundMixer +class SoundMixer { private: - IAudioDevice *_audioDevice; - Console *_console; + IAudioDevice* _audioDevice; + Console* _console; unique_ptr _equalizer; unique_ptr _resampler; shared_ptr _waveRecorder; - int16_t *_sampleBuffer = nullptr; + int16_t* _sampleBuffer = nullptr; int16_t _leftSample = 0; int16_t _rightSample = 0; - void ProcessEqualizer(int16_t *samples, uint32_t sampleCount); + void ProcessEqualizer(int16_t* samples, uint32_t sampleCount); public: - SoundMixer(Console *console); + SoundMixer(Console* console); ~SoundMixer(); - void PlayAudioBuffer(int16_t *samples, uint32_t sampleCount, uint32_t sourceRate); + void PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_t sourceRate); void StopAudio(bool clearBuffer = false); - void RegisterAudioDevice(IAudioDevice *audioDevice); + void RegisterAudioDevice(IAudioDevice* audioDevice); AudioStatistics GetStatistics(); double GetRateAdjustment(); void StartRecording(string filepath); void StopRecording(); bool IsRecording(); - void GetLastSamples(int16_t &left, int16_t &right); + void GetLastSamples(int16_t& left, int16_t& right); }; diff --git a/Core/SoundResampler.cpp b/Core/SoundResampler.cpp index 57adcf4..e43afb9 100644 --- a/Core/SoundResampler.cpp +++ b/Core/SoundResampler.cpp @@ -7,7 +7,7 @@ #include "VideoRenderer.h" #include "../Utilities/HermiteResampler.h" -SoundResampler::SoundResampler(Console *console) +SoundResampler::SoundResampler(Console* console) { _console = console; } @@ -25,12 +25,14 @@ double SoundResampler::GetTargetRateAdjustment() { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); bool isRecording = _console->GetSoundMixer()->IsRecording() || _console->GetVideoRenderer()->IsRecording(); - if(!isRecording && !cfg.DisableDynamicSampleRate) { + if (!isRecording && !cfg.DisableDynamicSampleRate) + { //Don't deviate from selected sample rate while recording //TODO: Have 2 output streams (one for recording, one for the speakers) AudioStatistics stats = _console->GetSoundMixer()->GetStatistics(); - if(stats.AverageLatency > 0 && _console->GetSettings()->GetEmulationSpeed() == 100) { + if (stats.AverageLatency > 0 && _console->GetSettings()->GetEmulationSpeed() == 100) + { //Try to stay within +/- 3ms of requested latency constexpr int32_t maxGap = 3; constexpr int32_t maxSubAdjustment = 3600; @@ -39,9 +41,12 @@ double SoundResampler::GetTargetRateAdjustment() double latencyGap = stats.AverageLatency - requestedLatency; double adjustment = std::min(0.0025, (std::ceil((std::abs(latencyGap) - maxGap) * 8)) * 0.00003125); - if(latencyGap < 0 && _underTarget < maxSubAdjustment) { + if (latencyGap < 0 && _underTarget < maxSubAdjustment) + { _underTarget++; - } else if(latencyGap > 0 && _underTarget > -maxSubAdjustment) { + } + else if (latencyGap > 0 && _underTarget > -maxSubAdjustment) + { _underTarget--; } @@ -49,21 +54,31 @@ double SoundResampler::GetTargetRateAdjustment() //This should slowly get us closer to the actual output rate of the sound card double subAdjustment = 0.00003125 * _underTarget / 180; - if(adjustment > 0) { - if(latencyGap > maxGap) { + if (adjustment > 0) + { + if (latencyGap > maxGap) + { _rateAdjustment = 1 - adjustment + subAdjustment; - } else if(latencyGap < -maxGap) { + } + else if (latencyGap < -maxGap) + { _rateAdjustment = 1 + adjustment + subAdjustment; } - } else if(std::abs(latencyGap) < 1) { + } + else if (std::abs(latencyGap) < 1) + { //Restore normal rate once we get within +/- 1ms _rateAdjustment = 1.0 + subAdjustment; } - } else { + } + else + { _underTarget = 0; _rateAdjustment = 1.0; } - } else { + } + else + { _underTarget = 0; _rateAdjustment = 1.0; } @@ -73,25 +88,31 @@ double SoundResampler::GetTargetRateAdjustment() void SoundResampler::UpdateTargetSampleRate(uint32_t sourceRate, uint32_t sampleRate) { double spcSampleRate = sourceRate; - if(_console->GetSettings()->GetVideoConfig().IntegerFpsMode) { + if (_console->GetSettings()->GetVideoConfig().IntegerFpsMode) + { //Adjust sample rate when running at 60.0 fps instead of 60.1 - switch(_console->GetRegion()) { - default: - case ConsoleRegion::Ntsc: spcSampleRate = sourceRate * (60.0 / _console->GetFps()); break; - case ConsoleRegion::Pal: spcSampleRate = sourceRate * (50.0 / _console->GetFps()); break; + switch (_console->GetRegion()) + { + default: + case ConsoleRegion::Ntsc: spcSampleRate = sourceRate * (60.0 / _console->GetFps()); + break; + case ConsoleRegion::Pal: spcSampleRate = sourceRate * (50.0 / _console->GetFps()); + break; } } double targetRate = sampleRate * GetTargetRateAdjustment(); - if(targetRate != _previousTargetRate || spcSampleRate != _prevSpcSampleRate) { + if (targetRate != _previousTargetRate || spcSampleRate != _prevSpcSampleRate) + { _previousTargetRate = targetRate; _prevSpcSampleRate = spcSampleRate; _resampler.SetSampleRates(spcSampleRate, targetRate); } } -uint32_t SoundResampler::Resample(int16_t *inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, int16_t *outSamples) +uint32_t SoundResampler::Resample(int16_t* inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, + int16_t* outSamples) { UpdateTargetSampleRate(sourceRate, sampleRate); return _resampler.Resample(inSamples, sampleCount, outSamples); -} \ No newline at end of file +} diff --git a/Core/SoundResampler.h b/Core/SoundResampler.h index 2c7bed8..33c7361 100644 --- a/Core/SoundResampler.h +++ b/Core/SoundResampler.h @@ -7,7 +7,7 @@ class Console; class SoundResampler { private: - Console *_console; + Console* _console; double _rateAdjustment = 1.0; double _previousTargetRate = 0; @@ -20,10 +20,11 @@ private: void UpdateTargetSampleRate(uint32_t sourceRate, uint32_t sampleRate); public: - SoundResampler(Console *console); + SoundResampler(Console* console); ~SoundResampler(); double GetRateAdjustment(); - uint32_t Resample(int16_t *inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, int16_t *outSamples); -}; \ No newline at end of file + uint32_t Resample(int16_t* inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, + int16_t* outSamples); +}; diff --git a/Core/Spc.Instructions.cpp b/Core/Spc.Instructions.cpp index 3e3e2b9..8f27871 100644 --- a/Core/Spc.Instructions.cpp +++ b/Core/Spc.Instructions.cpp @@ -15,266 +15,719 @@ void Spc::EndAddr() void Spc::Exec() { - switch(_opCode) { - case 0x00: NOP(); break; - case 0x01: TCALL<0>(); break; - case 0x02: Addr_Dir(); SET1<0>(); break; - case 0x03: Addr_Dir(); BBS<0>(); break; - case 0x04: Addr_Dir(); OR_Acc(); break; - case 0x05: Addr_Abs(); OR_Acc(); break; - case 0x06: Addr_IndX(); OR_Acc(); break; - case 0x07: Addr_DirIdxXInd(); OR_Acc(); break; - case 0x08: Addr_Imm(); OR_Imm(); break; - case 0x09: Addr_DirToDir(); OR(); break; - case 0x0A: Addr_AbsBit(); OR1(); break; - case 0x0B: Addr_Dir(); ASL(); break; - case 0x0C: Addr_Abs(); ASL(); break; - case 0x0D: PHP(); break; - case 0x0E: Addr_Abs(); TSET1(); break; - case 0x0F: BRK(); break; - case 0x10: Addr_Rel(); BPL(); break; - case 0x11: TCALL<1>(); break; - case 0x12: Addr_Dir(); CLR1<0>(); break; - case 0x13: Addr_Dir(); BBC<0>(); break; - case 0x14: Addr_DirIdxX(); OR_Acc(); break; - case 0x15: Addr_AbsIdxX(); OR_Acc(); break; - case 0x16: Addr_AbsIdxY(); OR_Acc(); break; - case 0x17: Addr_DirIndIdxY(); OR_Acc(); break; - case 0x18: Addr_DirImm(); OR(); break; - case 0x19: Addr_IndXToIndY(); OR(); break; - case 0x1A: Addr_Dir(); DECW(); break; - case 0x1B: Addr_DirIdxX(); ASL(); break; - case 0x1C: ASL_Acc(); break; - case 0x1D: DEX(); break; - case 0x1E: Addr_Abs(); CPX(); break; - case 0x1F: Addr_AbsIdxXInd(); JMP(); break; - case 0x20: CLRP(); break; - case 0x21: TCALL<2>(); break; - case 0x22: Addr_Dir(); SET1<1>(); break; - case 0x23: Addr_Dir(); BBS<1>(); break; - case 0x24: Addr_Dir(); AND_Acc(); break; - case 0x25: Addr_Abs(); AND_Acc(); break; - case 0x26: Addr_IndX(); AND_Acc(); break; - case 0x27: Addr_DirIdxXInd(); AND_Acc(); break; - case 0x28: Addr_Imm(); AND_Imm(); break; - case 0x29: Addr_DirToDir(); AND(); break; - case 0x2A: Addr_AbsBit(); NOR1(); break; - case 0x2B: Addr_Dir(); ROL(); break; - case 0x2C: Addr_Abs(); ROL(); break; - case 0x2D: PHA(); break; - case 0x2E: Addr_Dir(); CBNE(); break; - case 0x2F: Addr_Rel(); BRA(); break; - case 0x30: Addr_Rel(); BMI(); break; - case 0x31: TCALL<3>(); break; - case 0x32: Addr_Dir(); CLR1<1>(); break; - case 0x33: Addr_Dir(); BBC<1>(); break; - case 0x34: Addr_DirIdxX(); AND_Acc(); break; - case 0x35: Addr_AbsIdxX(); AND_Acc(); break; - case 0x36: Addr_AbsIdxY(); AND_Acc(); break; - case 0x37: Addr_DirIndIdxY(); AND_Acc(); break; - case 0x38: Addr_DirImm(); AND(); break; - case 0x39: Addr_IndXToIndY(); AND(); break; - case 0x3A: Addr_Dir(); INCW(); break; - case 0x3B: Addr_DirIdxX(); ROL(); break; - case 0x3C: ROL_Acc(); break; - case 0x3D: INX(); break; - case 0x3E: Addr_Dir(); CPX(); break; - case 0x3F: Addr_Abs(); JSR(); break; - case 0x40: SETP(); break; - case 0x41: TCALL<4>(); break; - case 0x42: Addr_Dir(); SET1<2>(); break; - case 0x43: Addr_Dir(); BBS<2>(); break; - case 0x44: Addr_Dir(); EOR_Acc(); break; - case 0x45: Addr_Abs(); EOR_Acc(); break; - case 0x46: Addr_IndX(); EOR_Acc(); break; - case 0x47: Addr_DirIdxXInd(); EOR_Acc(); break; - case 0x48: Addr_Imm(); EOR_Imm(); break; - case 0x49: Addr_DirToDir(); EOR(); break; - case 0x4A: Addr_AbsBit(); AND1(); break; - case 0x4B: Addr_Dir(); LSR(); break; - case 0x4C: Addr_Abs(); LSR(); break; - case 0x4D: PHX(); break; - case 0x4E: Addr_Abs(); TCLR1(); break; - case 0x4F: PCALL(); break; - case 0x50: Addr_Rel(); BVC(); break; - case 0x51: TCALL<5>(); break; - case 0x52: Addr_Dir(); CLR1<2>(); break; - case 0x53: Addr_Dir(); BBC<2>(); break; - case 0x54: Addr_DirIdxX(); EOR_Acc(); break; - case 0x55: Addr_AbsIdxX(); EOR_Acc(); break; - case 0x56: Addr_AbsIdxY(); EOR_Acc(); break; - case 0x57: Addr_DirIndIdxY(); EOR_Acc(); break; - case 0x58: Addr_DirImm(); EOR(); break; - case 0x59: Addr_IndXToIndY(); EOR(); break; - case 0x5A: Addr_Dir(); CMPW(); break; - case 0x5B: Addr_DirIdxX(); LSR(); break; - case 0x5C: LSR_Acc(); break; - case 0x5D: TAX(); break; - case 0x5E: Addr_Abs(); CPY(); break; - case 0x5F: Addr_Abs(); JMP(); break; - case 0x60: CLRC(); break; - case 0x61: TCALL<6>(); break; - case 0x62: Addr_Dir(); SET1<3>(); break; - case 0x63: Addr_Dir(); BBS<3>(); break; - case 0x64: Addr_Dir(); CMP_Acc(); break; - case 0x65: Addr_Abs(); CMP_Acc(); break; - case 0x66: Addr_IndX(); CMP_Acc(); break; - case 0x67: Addr_DirIdxXInd(); CMP_Acc(); break; - case 0x68: Addr_Imm(); CMP_Imm(); break; - case 0x69: Addr_DirToDir(); CMP(); break; - case 0x6A: Addr_AbsBit(); NAND1(); break; - case 0x6B: Addr_Dir(); ROR(); break; - case 0x6C: Addr_Abs(); ROR(); break; - case 0x6D: PHY(); break; - case 0x6E: Addr_Dir(); DBNZ(); break; - case 0x6F: RTS(); break; - case 0x70: Addr_Rel(); BVS(); break; - case 0x71: TCALL<7>(); break; - case 0x72: Addr_Dir(); CLR1<3>(); break; - case 0x73: Addr_Dir(); BBC<3>(); break; - case 0x74: Addr_DirIdxX(); CMP_Acc(); break; - case 0x75: Addr_AbsIdxX(); CMP_Acc(); break; - case 0x76: Addr_AbsIdxY(); CMP_Acc(); break; - case 0x77: Addr_DirIndIdxY(); CMP_Acc(); break; - case 0x78: Addr_DirImm(); CMP(); break; - case 0x79: Addr_IndXToIndY(); CMP(); break; - case 0x7A: Addr_Dir(); ADDW(); break; - case 0x7B: Addr_DirIdxX(); ROR(); break; - case 0x7C: ROR_Acc(); break; - case 0x7D: TXA(); break; - case 0x7E: Addr_Dir(); CPY(); break; - case 0x7F: RTI(); break; - case 0x80: SETC(); break; - case 0x81: TCALL<8>(); break; - case 0x82: Addr_Dir(); SET1<4>(); break; - case 0x83: Addr_Dir(); BBS<4>(); break; - case 0x84: Addr_Dir(); ADC_Acc(); break; - case 0x85: Addr_Abs(); ADC_Acc(); break; - case 0x86: Addr_IndX(); ADC_Acc(); break; - case 0x87: Addr_DirIdxXInd(); ADC_Acc(); break; - case 0x88: Addr_Imm(); ADC_Imm(); break; - case 0x89: Addr_DirToDir(); ADC(); break; - case 0x8A: Addr_AbsBit(); EOR1(); break; - case 0x8B: Addr_Dir(); DEC(); break; - case 0x8C: Addr_Abs(); DEC(); break; - case 0x8D: Addr_Imm(); LDY_Imm(); break; - case 0x8E: PLP(); break; - case 0x8F: Addr_DirImm(); MOV_Imm(); break; - case 0x90: Addr_Rel(); BCC(); break; - case 0x91: TCALL<9>(); break; - case 0x92: Addr_Dir(); CLR1<4>(); break; - case 0x93: Addr_Dir(); BBC<4>(); break; - case 0x94: Addr_DirIdxX(); ADC_Acc(); break; - case 0x95: Addr_AbsIdxX(); ADC_Acc(); break; - case 0x96: Addr_AbsIdxY(); ADC_Acc(); break; - case 0x97: Addr_DirIndIdxY(); ADC_Acc(); break; - case 0x98: Addr_DirImm(); ADC(); break; - case 0x99: Addr_IndXToIndY(); ADC(); break; - case 0x9A: Addr_Dir(); SUBW(); break; - case 0x9B: Addr_DirIdxX(); DEC(); break; - case 0x9C: DEC_Acc(); break; - case 0x9D: TSX(); break; - case 0x9E: DIV(); break; - case 0x9F: XCN(); break; - case 0xA0: EI(); break; - case 0xA1: TCALL<10>(); break; - case 0xA2: Addr_Dir(); SET1<5>(); break; - case 0xA3: Addr_Dir(); BBS<5>(); break; - case 0xA4: Addr_Dir(); SBC_Acc(); break; - case 0xA5: Addr_Abs(); SBC_Acc(); break; - case 0xA6: Addr_IndX(); SBC_Acc(); break; - case 0xA7: Addr_DirIdxXInd(); SBC_Acc(); break; - case 0xA8: Addr_Imm(); SBC_Imm(); break; - case 0xA9: Addr_DirToDir(); SBC(); break; - case 0xAA: Addr_AbsBit(); LDC(); break; - case 0xAB: Addr_Dir(); INC(); break; - case 0xAC: Addr_Abs(); INC(); break; - case 0xAD: Addr_Imm(); CPY_Imm(); break; - case 0xAE: PLA(); break; - case 0xAF: Addr_IndX(); STA_AutoIncX(); break; - case 0xB0: Addr_Rel(); BCS(); break; - case 0xB1: TCALL<11>(); break; - case 0xB2: Addr_Dir(); CLR1<5>(); break; - case 0xB3: Addr_Dir(); BBC<5>(); break; - case 0xB4: Addr_DirIdxX(); SBC_Acc(); break; - case 0xB5: Addr_AbsIdxX(); SBC_Acc(); break; - case 0xB6: Addr_AbsIdxY(); SBC_Acc(); break; - case 0xB7: Addr_DirIndIdxY(); SBC_Acc(); break; - case 0xB8: Addr_DirImm(); SBC(); break; - case 0xB9: Addr_IndXToIndY(); SBC(); break; - case 0xBA: Addr_Dir(); LDW(); break; - case 0xBB: Addr_DirIdxX(); INC(); break; - case 0xBC: INC_Acc(); break; - case 0xBD: TXS(); break; - case 0xBE: DAS(); break; - case 0xBF: Addr_IndX(); LDA_AutoIncX(); break; - case 0xC0: DI(); break; - case 0xC1: TCALL<12>(); break; - case 0xC2: Addr_Dir(); SET1<6>(); break; - case 0xC3: Addr_Dir(); BBS<6>(); break; - case 0xC4: Addr_Dir(); STA(); break; - case 0xC5: Addr_Abs(); STA(); break; - case 0xC6: Addr_IndX(); STA(); break; - case 0xC7: Addr_DirIdxXInd(); STA(); break; - case 0xC8: Addr_Imm(); CPX_Imm(); break; - case 0xC9: Addr_Abs(); STX(); break; - case 0xCA: Addr_AbsBit(); STC(); break; - case 0xCB: Addr_Dir(); STY(); break; - case 0xCC: Addr_Abs(); STY(); break; - case 0xCD: Addr_Imm(); LDX_Imm(); break; - case 0xCE: PLX(); break; - case 0xCF: MUL(); break; - case 0xD0: Addr_Rel(); BNE(); break; - case 0xD1: TCALL<13>(); break; - case 0xD2: Addr_Dir(); CLR1<6>(); break; - case 0xD3: Addr_Dir(); BBC<6>(); break; - case 0xD4: Addr_DirIdxX(); STA(); break; - case 0xD5: Addr_AbsIdxX(); STA(); break; - case 0xD6: Addr_AbsIdxY(); STA(); break; - case 0xD7: Addr_DirIndIdxY(); STA(); break; - case 0xD8: Addr_Dir(); STX(); break; - case 0xD9: Addr_DirIdxY(); STX(); break; - case 0xDA: Addr_Dir(); STW(); break; - case 0xDB: Addr_DirIdxX(); STY(); break; - case 0xDC: DEY(); break; - case 0xDD: TYA(); break; - case 0xDE: Addr_DirIdxX(); CBNE(); break; - case 0xDF: DAA(); break; - case 0xE0: CLRV(); break; - case 0xE1: TCALL<14>(); break; - case 0xE2: Addr_Dir(); SET1<7>(); break; - case 0xE3: Addr_Dir(); BBS<7>(); break; - case 0xE4: Addr_Dir(); LDA(); break; - case 0xE5: Addr_Abs(); LDA(); break; - case 0xE6: Addr_IndX(); LDA(); break; - case 0xE7: Addr_DirIdxXInd(); LDA(); break; - case 0xE8: Addr_Imm(); LDA_Imm(); break; - case 0xE9: Addr_Abs(); LDX(); break; - case 0xEA: Addr_AbsBit(); NOT1(); break; - case 0xEB: Addr_Dir(); LDY(); break; - case 0xEC: Addr_Abs(); LDY(); break; - case 0xED: NOTC(); break; - case 0xEE: PLY(); break; - case 0xEF: SLEEP(); break; - case 0xF0: Addr_Rel(); BEQ(); break; - case 0xF1: TCALL<15>(); break; - case 0xF2: Addr_Dir(); CLR1<7>(); break; - case 0xF3: Addr_Dir(); BBC<7>(); break; - case 0xF4: Addr_DirIdxX(); LDA(); break; - case 0xF5: Addr_AbsIdxX(); LDA(); break; - case 0xF6: Addr_AbsIdxY(); LDA(); break; - case 0xF7: Addr_DirIndIdxY(); LDA(); break; - case 0xF8: Addr_Dir(); LDX(); break; - case 0xF9: Addr_DirIdxY(); LDX(); break; - case 0xFA: Addr_DirToDir(); MOV(); break; - case 0xFB: Addr_DirIdxX(); LDY(); break; - case 0xFC: INY(); break; - case 0xFD: TAY(); break; - case 0xFE: DBNZ_Y(); break; - case 0xFF: STOP(); break; + switch (_opCode) + { + case 0x00: NOP(); + break; + case 0x01: TCALL<0>(); + break; + case 0x02: Addr_Dir(); + SET1<0>(); + break; + case 0x03: Addr_Dir(); + BBS<0>(); + break; + case 0x04: Addr_Dir(); + OR_Acc(); + break; + case 0x05: Addr_Abs(); + OR_Acc(); + break; + case 0x06: Addr_IndX(); + OR_Acc(); + break; + case 0x07: Addr_DirIdxXInd(); + OR_Acc(); + break; + case 0x08: Addr_Imm(); + OR_Imm(); + break; + case 0x09: Addr_DirToDir(); + OR(); + break; + case 0x0A: Addr_AbsBit(); + OR1(); + break; + case 0x0B: Addr_Dir(); + ASL(); + break; + case 0x0C: Addr_Abs(); + ASL(); + break; + case 0x0D: PHP(); + break; + case 0x0E: Addr_Abs(); + TSET1(); + break; + case 0x0F: BRK(); + break; + case 0x10: Addr_Rel(); + BPL(); + break; + case 0x11: TCALL<1>(); + break; + case 0x12: Addr_Dir(); + CLR1<0>(); + break; + case 0x13: Addr_Dir(); + BBC<0>(); + break; + case 0x14: Addr_DirIdxX(); + OR_Acc(); + break; + case 0x15: Addr_AbsIdxX(); + OR_Acc(); + break; + case 0x16: Addr_AbsIdxY(); + OR_Acc(); + break; + case 0x17: Addr_DirIndIdxY(); + OR_Acc(); + break; + case 0x18: Addr_DirImm(); + OR(); + break; + case 0x19: Addr_IndXToIndY(); + OR(); + break; + case 0x1A: Addr_Dir(); + DECW(); + break; + case 0x1B: Addr_DirIdxX(); + ASL(); + break; + case 0x1C: ASL_Acc(); + break; + case 0x1D: DEX(); + break; + case 0x1E: Addr_Abs(); + CPX(); + break; + case 0x1F: Addr_AbsIdxXInd(); + JMP(); + break; + case 0x20: CLRP(); + break; + case 0x21: TCALL<2>(); + break; + case 0x22: Addr_Dir(); + SET1<1>(); + break; + case 0x23: Addr_Dir(); + BBS<1>(); + break; + case 0x24: Addr_Dir(); + AND_Acc(); + break; + case 0x25: Addr_Abs(); + AND_Acc(); + break; + case 0x26: Addr_IndX(); + AND_Acc(); + break; + case 0x27: Addr_DirIdxXInd(); + AND_Acc(); + break; + case 0x28: Addr_Imm(); + AND_Imm(); + break; + case 0x29: Addr_DirToDir(); + AND(); + break; + case 0x2A: Addr_AbsBit(); + NOR1(); + break; + case 0x2B: Addr_Dir(); + ROL(); + break; + case 0x2C: Addr_Abs(); + ROL(); + break; + case 0x2D: PHA(); + break; + case 0x2E: Addr_Dir(); + CBNE(); + break; + case 0x2F: Addr_Rel(); + BRA(); + break; + case 0x30: Addr_Rel(); + BMI(); + break; + case 0x31: TCALL<3>(); + break; + case 0x32: Addr_Dir(); + CLR1<1>(); + break; + case 0x33: Addr_Dir(); + BBC<1>(); + break; + case 0x34: Addr_DirIdxX(); + AND_Acc(); + break; + case 0x35: Addr_AbsIdxX(); + AND_Acc(); + break; + case 0x36: Addr_AbsIdxY(); + AND_Acc(); + break; + case 0x37: Addr_DirIndIdxY(); + AND_Acc(); + break; + case 0x38: Addr_DirImm(); + AND(); + break; + case 0x39: Addr_IndXToIndY(); + AND(); + break; + case 0x3A: Addr_Dir(); + INCW(); + break; + case 0x3B: Addr_DirIdxX(); + ROL(); + break; + case 0x3C: ROL_Acc(); + break; + case 0x3D: INX(); + break; + case 0x3E: Addr_Dir(); + CPX(); + break; + case 0x3F: Addr_Abs(); + JSR(); + break; + case 0x40: SETP(); + break; + case 0x41: TCALL<4>(); + break; + case 0x42: Addr_Dir(); + SET1<2>(); + break; + case 0x43: Addr_Dir(); + BBS<2>(); + break; + case 0x44: Addr_Dir(); + EOR_Acc(); + break; + case 0x45: Addr_Abs(); + EOR_Acc(); + break; + case 0x46: Addr_IndX(); + EOR_Acc(); + break; + case 0x47: Addr_DirIdxXInd(); + EOR_Acc(); + break; + case 0x48: Addr_Imm(); + EOR_Imm(); + break; + case 0x49: Addr_DirToDir(); + EOR(); + break; + case 0x4A: Addr_AbsBit(); + AND1(); + break; + case 0x4B: Addr_Dir(); + LSR(); + break; + case 0x4C: Addr_Abs(); + LSR(); + break; + case 0x4D: PHX(); + break; + case 0x4E: Addr_Abs(); + TCLR1(); + break; + case 0x4F: PCALL(); + break; + case 0x50: Addr_Rel(); + BVC(); + break; + case 0x51: TCALL<5>(); + break; + case 0x52: Addr_Dir(); + CLR1<2>(); + break; + case 0x53: Addr_Dir(); + BBC<2>(); + break; + case 0x54: Addr_DirIdxX(); + EOR_Acc(); + break; + case 0x55: Addr_AbsIdxX(); + EOR_Acc(); + break; + case 0x56: Addr_AbsIdxY(); + EOR_Acc(); + break; + case 0x57: Addr_DirIndIdxY(); + EOR_Acc(); + break; + case 0x58: Addr_DirImm(); + EOR(); + break; + case 0x59: Addr_IndXToIndY(); + EOR(); + break; + case 0x5A: Addr_Dir(); + CMPW(); + break; + case 0x5B: Addr_DirIdxX(); + LSR(); + break; + case 0x5C: LSR_Acc(); + break; + case 0x5D: TAX(); + break; + case 0x5E: Addr_Abs(); + CPY(); + break; + case 0x5F: Addr_Abs(); + JMP(); + break; + case 0x60: CLRC(); + break; + case 0x61: TCALL<6>(); + break; + case 0x62: Addr_Dir(); + SET1<3>(); + break; + case 0x63: Addr_Dir(); + BBS<3>(); + break; + case 0x64: Addr_Dir(); + CMP_Acc(); + break; + case 0x65: Addr_Abs(); + CMP_Acc(); + break; + case 0x66: Addr_IndX(); + CMP_Acc(); + break; + case 0x67: Addr_DirIdxXInd(); + CMP_Acc(); + break; + case 0x68: Addr_Imm(); + CMP_Imm(); + break; + case 0x69: Addr_DirToDir(); + CMP(); + break; + case 0x6A: Addr_AbsBit(); + NAND1(); + break; + case 0x6B: Addr_Dir(); + ROR(); + break; + case 0x6C: Addr_Abs(); + ROR(); + break; + case 0x6D: PHY(); + break; + case 0x6E: Addr_Dir(); + DBNZ(); + break; + case 0x6F: RTS(); + break; + case 0x70: Addr_Rel(); + BVS(); + break; + case 0x71: TCALL<7>(); + break; + case 0x72: Addr_Dir(); + CLR1<3>(); + break; + case 0x73: Addr_Dir(); + BBC<3>(); + break; + case 0x74: Addr_DirIdxX(); + CMP_Acc(); + break; + case 0x75: Addr_AbsIdxX(); + CMP_Acc(); + break; + case 0x76: Addr_AbsIdxY(); + CMP_Acc(); + break; + case 0x77: Addr_DirIndIdxY(); + CMP_Acc(); + break; + case 0x78: Addr_DirImm(); + CMP(); + break; + case 0x79: Addr_IndXToIndY(); + CMP(); + break; + case 0x7A: Addr_Dir(); + ADDW(); + break; + case 0x7B: Addr_DirIdxX(); + ROR(); + break; + case 0x7C: ROR_Acc(); + break; + case 0x7D: TXA(); + break; + case 0x7E: Addr_Dir(); + CPY(); + break; + case 0x7F: RTI(); + break; + case 0x80: SETC(); + break; + case 0x81: TCALL<8>(); + break; + case 0x82: Addr_Dir(); + SET1<4>(); + break; + case 0x83: Addr_Dir(); + BBS<4>(); + break; + case 0x84: Addr_Dir(); + ADC_Acc(); + break; + case 0x85: Addr_Abs(); + ADC_Acc(); + break; + case 0x86: Addr_IndX(); + ADC_Acc(); + break; + case 0x87: Addr_DirIdxXInd(); + ADC_Acc(); + break; + case 0x88: Addr_Imm(); + ADC_Imm(); + break; + case 0x89: Addr_DirToDir(); + ADC(); + break; + case 0x8A: Addr_AbsBit(); + EOR1(); + break; + case 0x8B: Addr_Dir(); + DEC(); + break; + case 0x8C: Addr_Abs(); + DEC(); + break; + case 0x8D: Addr_Imm(); + LDY_Imm(); + break; + case 0x8E: PLP(); + break; + case 0x8F: Addr_DirImm(); + MOV_Imm(); + break; + case 0x90: Addr_Rel(); + BCC(); + break; + case 0x91: TCALL<9>(); + break; + case 0x92: Addr_Dir(); + CLR1<4>(); + break; + case 0x93: Addr_Dir(); + BBC<4>(); + break; + case 0x94: Addr_DirIdxX(); + ADC_Acc(); + break; + case 0x95: Addr_AbsIdxX(); + ADC_Acc(); + break; + case 0x96: Addr_AbsIdxY(); + ADC_Acc(); + break; + case 0x97: Addr_DirIndIdxY(); + ADC_Acc(); + break; + case 0x98: Addr_DirImm(); + ADC(); + break; + case 0x99: Addr_IndXToIndY(); + ADC(); + break; + case 0x9A: Addr_Dir(); + SUBW(); + break; + case 0x9B: Addr_DirIdxX(); + DEC(); + break; + case 0x9C: DEC_Acc(); + break; + case 0x9D: TSX(); + break; + case 0x9E: DIV(); + break; + case 0x9F: XCN(); + break; + case 0xA0: EI(); + break; + case 0xA1: TCALL<10>(); + break; + case 0xA2: Addr_Dir(); + SET1<5>(); + break; + case 0xA3: Addr_Dir(); + BBS<5>(); + break; + case 0xA4: Addr_Dir(); + SBC_Acc(); + break; + case 0xA5: Addr_Abs(); + SBC_Acc(); + break; + case 0xA6: Addr_IndX(); + SBC_Acc(); + break; + case 0xA7: Addr_DirIdxXInd(); + SBC_Acc(); + break; + case 0xA8: Addr_Imm(); + SBC_Imm(); + break; + case 0xA9: Addr_DirToDir(); + SBC(); + break; + case 0xAA: Addr_AbsBit(); + LDC(); + break; + case 0xAB: Addr_Dir(); + INC(); + break; + case 0xAC: Addr_Abs(); + INC(); + break; + case 0xAD: Addr_Imm(); + CPY_Imm(); + break; + case 0xAE: PLA(); + break; + case 0xAF: Addr_IndX(); + STA_AutoIncX(); + break; + case 0xB0: Addr_Rel(); + BCS(); + break; + case 0xB1: TCALL<11>(); + break; + case 0xB2: Addr_Dir(); + CLR1<5>(); + break; + case 0xB3: Addr_Dir(); + BBC<5>(); + break; + case 0xB4: Addr_DirIdxX(); + SBC_Acc(); + break; + case 0xB5: Addr_AbsIdxX(); + SBC_Acc(); + break; + case 0xB6: Addr_AbsIdxY(); + SBC_Acc(); + break; + case 0xB7: Addr_DirIndIdxY(); + SBC_Acc(); + break; + case 0xB8: Addr_DirImm(); + SBC(); + break; + case 0xB9: Addr_IndXToIndY(); + SBC(); + break; + case 0xBA: Addr_Dir(); + LDW(); + break; + case 0xBB: Addr_DirIdxX(); + INC(); + break; + case 0xBC: INC_Acc(); + break; + case 0xBD: TXS(); + break; + case 0xBE: DAS(); + break; + case 0xBF: Addr_IndX(); + LDA_AutoIncX(); + break; + case 0xC0: DI(); + break; + case 0xC1: TCALL<12>(); + break; + case 0xC2: Addr_Dir(); + SET1<6>(); + break; + case 0xC3: Addr_Dir(); + BBS<6>(); + break; + case 0xC4: Addr_Dir(); + STA(); + break; + case 0xC5: Addr_Abs(); + STA(); + break; + case 0xC6: Addr_IndX(); + STA(); + break; + case 0xC7: Addr_DirIdxXInd(); + STA(); + break; + case 0xC8: Addr_Imm(); + CPX_Imm(); + break; + case 0xC9: Addr_Abs(); + STX(); + break; + case 0xCA: Addr_AbsBit(); + STC(); + break; + case 0xCB: Addr_Dir(); + STY(); + break; + case 0xCC: Addr_Abs(); + STY(); + break; + case 0xCD: Addr_Imm(); + LDX_Imm(); + break; + case 0xCE: PLX(); + break; + case 0xCF: MUL(); + break; + case 0xD0: Addr_Rel(); + BNE(); + break; + case 0xD1: TCALL<13>(); + break; + case 0xD2: Addr_Dir(); + CLR1<6>(); + break; + case 0xD3: Addr_Dir(); + BBC<6>(); + break; + case 0xD4: Addr_DirIdxX(); + STA(); + break; + case 0xD5: Addr_AbsIdxX(); + STA(); + break; + case 0xD6: Addr_AbsIdxY(); + STA(); + break; + case 0xD7: Addr_DirIndIdxY(); + STA(); + break; + case 0xD8: Addr_Dir(); + STX(); + break; + case 0xD9: Addr_DirIdxY(); + STX(); + break; + case 0xDA: Addr_Dir(); + STW(); + break; + case 0xDB: Addr_DirIdxX(); + STY(); + break; + case 0xDC: DEY(); + break; + case 0xDD: TYA(); + break; + case 0xDE: Addr_DirIdxX(); + CBNE(); + break; + case 0xDF: DAA(); + break; + case 0xE0: CLRV(); + break; + case 0xE1: TCALL<14>(); + break; + case 0xE2: Addr_Dir(); + SET1<7>(); + break; + case 0xE3: Addr_Dir(); + BBS<7>(); + break; + case 0xE4: Addr_Dir(); + LDA(); + break; + case 0xE5: Addr_Abs(); + LDA(); + break; + case 0xE6: Addr_IndX(); + LDA(); + break; + case 0xE7: Addr_DirIdxXInd(); + LDA(); + break; + case 0xE8: Addr_Imm(); + LDA_Imm(); + break; + case 0xE9: Addr_Abs(); + LDX(); + break; + case 0xEA: Addr_AbsBit(); + NOT1(); + break; + case 0xEB: Addr_Dir(); + LDY(); + break; + case 0xEC: Addr_Abs(); + LDY(); + break; + case 0xED: NOTC(); + break; + case 0xEE: PLY(); + break; + case 0xEF: SLEEP(); + break; + case 0xF0: Addr_Rel(); + BEQ(); + break; + case 0xF1: TCALL<15>(); + break; + case 0xF2: Addr_Dir(); + CLR1<7>(); + break; + case 0xF3: Addr_Dir(); + BBC<7>(); + break; + case 0xF4: Addr_DirIdxX(); + LDA(); + break; + case 0xF5: Addr_AbsIdxX(); + LDA(); + break; + case 0xF6: Addr_AbsIdxY(); + LDA(); + break; + case 0xF7: Addr_DirIndIdxY(); + LDA(); + break; + case 0xF8: Addr_Dir(); + LDX(); + break; + case 0xF9: Addr_DirIdxY(); + LDX(); + break; + case 0xFA: Addr_DirToDir(); + MOV(); + break; + case 0xFB: Addr_DirIdxX(); + LDY(); + break; + case 0xFC: INY(); + break; + case 0xFD: TAY(); + break; + case 0xFE: DBNZ_Y(); + break; + case 0xFF: STOP(); + break; } - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _opStep = SpcOpStep::Operation; } } @@ -284,7 +737,8 @@ void Spc::Exec() //***************** void Spc::Addr_Dir() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = GetDirectAddress(ReadOperandByte()); EndAddr(); } @@ -292,80 +746,112 @@ void Spc::Addr_Dir() void Spc::Addr_DirIdxX() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.X); break; - case 1: Idle(); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.X); + break; + case 1: Idle(); + EndAddr(); + break; } } } void Spc::Addr_DirIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.Y); break; - case 1: Idle(); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.Y); + break; + case 1: Idle(); + EndAddr(); + break; } } } void Spc::Addr_DirToDir() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); break; - case 1: _operandA = Read(_tmp1); break; - case 2: _operandB = GetDirectAddress(ReadOperandByte()); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); + break; + case 1: _operandA = Read(_tmp1); + break; + case 2: _operandB = GetDirectAddress(ReadOperandByte()); + EndAddr(); + break; } } } void Spc::Addr_DirImm() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = ReadOperandByte(); break; - case 1: _operandB = GetDirectAddress(ReadOperandByte()); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = ReadOperandByte(); + break; + case 1: _operandB = GetDirectAddress(ReadOperandByte()); + EndAddr(); + break; } } } void Spc::Addr_DirIdxXInd() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte() + _state.X); break; - case 1: Idle(); break; - case 2: _tmp2 = Read(_tmp1); break; - case 3: - _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); - _operandA = (_tmp3 << 8) | _tmp2; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte() + _state.X); + break; + case 1: Idle(); + break; + case 2: _tmp2 = Read(_tmp1); + break; + case 3: + _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); + _operandA = (_tmp3 << 8) | _tmp2; + EndAddr(); + break; } } } void Spc::Addr_DirIndIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); break; - case 1: _tmp2 = Read(_tmp1); break; - case 2: _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); break; - case 4: - Idle(); - _operandA = ((_tmp3 << 8) | _tmp2) + _state.Y; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); + break; + case 1: _tmp2 = Read(_tmp1); + break; + case 2: _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); + break; + case 4: + Idle(); + _operandA = ((_tmp3 << 8) | _tmp2) + _state.Y; + EndAddr(); + break; } } } void Spc::Addr_IndX() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { DummyRead(); _operandA = GetDirectAddress(_state.X); EndAddr(); @@ -374,82 +860,97 @@ void Spc::Addr_IndX() void Spc::Addr_IndXToIndY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - _operandA = Read(GetDirectAddress(_state.Y)); - _operandB = GetDirectAddress(_state.X); - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + _operandA = Read(GetDirectAddress(_state.Y)); + _operandB = GetDirectAddress(_state.X); + EndAddr(); + break; } } } void Spc::Addr_Abs() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + EndAddr(); + break; } } } void Spc::Addr_AbsBit() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - _operandB = _operandA >> 13; - _operandA = _operandA & 0x1FFF; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + _operandB = _operandA >> 13; + _operandA = _operandA & 0x1FFF; + EndAddr(); + break; } } } void Spc::Addr_AbsIdxX() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + break; - case 2: - Idle(); - _operandA += _state.X; - EndAddr(); - break; + case 2: + Idle(); + _operandA += _state.X; + EndAddr(); + break; } } } void Spc::Addr_AbsIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - break; - - case 2: - Idle(); - _operandA += _state.Y; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + break; + + case 2: + Idle(); + _operandA += _state.Y; + EndAddr(); + break; } } } @@ -457,12 +958,17 @@ void Spc::Addr_AbsIdxY() void Spc::Addr_AbsIdxXInd() { //Used by JMP only - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: _tmp2 = ReadOperandByte(); break; - case 2: Idle(); break; - case 3: + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: _tmp2 = ReadOperandByte(); + break; + case 2: Idle(); + break; + case 3: { uint16_t addr = ((_tmp2 << 8) | _tmp1); _tmp1 = Read(addr + _state.X); @@ -477,7 +983,8 @@ void Spc::Addr_AbsIdxXInd() void Spc::Addr_Rel() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = ReadOperandByte(); EndAddr(); } @@ -485,7 +992,8 @@ void Spc::Addr_Rel() void Spc::Addr_Imm() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = ReadOperandByte(); EndAddr(); } @@ -496,84 +1004,109 @@ void Spc::Addr_Imm() //***************** void Spc::STA() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.A); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.A); + EndOp(); + break; } } } void Spc::STX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.X); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.X); + EndOp(); + break; } } } void Spc::STY() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.Y); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.Y); + EndOp(); + break; } } } void Spc::STW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: DummyRead(_operandA); break; - case 1: Write(_operandA, _state.A); break; - case 2: - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - Write(msbAddress, _state.Y); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: DummyRead(_operandA); + break; + case 1: Write(_operandA, _state.A); + break; + case 2: + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + Write(msbAddress, _state.Y); + EndOp(); + break; } } } void Spc::STA_AutoIncX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Write(_operandA, _state.A); - _state.X++; - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Write(_operandA, _state.A); + _state.X++; + EndOp(); + break; } } } void Spc::LDA_AutoIncX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _state.A = Read(_operandA); - SetZeroNegativeFlags(_state.A); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _state.A = Read(_operandA); + SetZeroNegativeFlags(_state.A); + break; - case 1: - Idle(); - _state.X++; - EndOp(); - break; + case 1: + Idle(); + _state.X++; + EndOp(); + break; } } } void Spc::LDA() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -582,7 +1115,8 @@ void Spc::LDA() void Spc::LDA_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = (uint8_t)_operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -591,7 +1125,8 @@ void Spc::LDA_Imm() void Spc::LDX() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.X = GetByteValue(); SetZeroNegativeFlags(_state.X); EndOp(); @@ -600,7 +1135,8 @@ void Spc::LDX() void Spc::LDX_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.X = (uint8_t)_operandA; SetZeroNegativeFlags(_state.X); EndOp(); @@ -609,7 +1145,8 @@ void Spc::LDX_Imm() void Spc::LDY() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.Y = GetByteValue(); SetZeroNegativeFlags(_state.Y); EndOp(); @@ -618,7 +1155,8 @@ void Spc::LDY() void Spc::LDY_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.Y = (uint8_t)_operandA; SetZeroNegativeFlags(_state.Y); EndOp(); @@ -627,23 +1165,27 @@ void Spc::LDY_Imm() void Spc::LDW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = (msb << 8) | _tmp1; - _state.A = (uint8_t)value; - _state.Y = (value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = (msb << 8) | _tmp1; + _state.A = (uint8_t)value; + _state.Y = (value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } -void Spc::Transfer(uint8_t &dst, uint8_t src) +void Spc::Transfer(uint8_t& dst, uint8_t src) { DummyRead(); dst = src; @@ -685,7 +1227,8 @@ void Spc::TXS() void Spc::MOV() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Write(_operandB, (uint8_t)_operandA); EndOp(); } @@ -693,10 +1236,15 @@ void Spc::MOV() void Spc::MOV_Imm() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: DummyRead(_operandB); break; - case 1: Write(_operandB, (uint8_t)_operandA); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: DummyRead(_operandB); + break; + case 1: Write(_operandB, (uint8_t)_operandA); + EndOp(); + break; } } } @@ -708,13 +1256,16 @@ uint8_t Spc::Add(uint8_t a, uint8_t b) ClearFlags(SpcFlags::Carry | SpcFlags::Negative | SpcFlags::Zero | SpcFlags::Overflow | SpcFlags::HalfCarry); - if(~(a ^ b) & (a ^ result) & 0x80) { + if (~(a ^ b) & (a ^ result) & 0x80) + { SetFlags(SpcFlags::Overflow); } - if(result > 0xFF) { + if (result > 0xFF) + { SetFlags(SpcFlags::Carry); } - if(((result & 0x0F) - subResult) & 0x10) { + if (((result & 0x0F) - subResult) & 0x10) + { SetFlags(SpcFlags::HalfCarry); } SetZeroNegativeFlags((uint8_t)result); @@ -727,9 +1278,12 @@ uint8_t Spc::Sub(uint8_t a, uint8_t b) uint32_t carryCalc = a - b - ((_state.PS & SpcFlags::Carry) ^ 0x01); uint8_t result = Add(a, ~b); - if(carryCalc <= 0xFF) { + if (carryCalc <= 0xFF) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } @@ -738,24 +1292,27 @@ uint8_t Spc::Sub(uint8_t a, uint8_t b) void Spc::ADC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _tmp1 = (uint8_t)_operandA; - _tmp2 = Read(_operandB); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _tmp1 = (uint8_t)_operandA; + _tmp2 = Read(_operandB); + break; - case 1: - Write(_operandB, Add((uint8_t)_tmp2, (uint8_t)_tmp1)); - EndOp(); - break; + case 1: + Write(_operandB, Add((uint8_t)_tmp2, (uint8_t)_tmp1)); + EndOp(); + break; } } } void Spc::ADC_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = Add(_state.A, GetByteValue()); EndOp(); } @@ -763,7 +1320,8 @@ void Spc::ADC_Acc() void Spc::ADC_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = Add(_state.A, (uint8_t)_operandA); EndOp(); } @@ -771,59 +1329,69 @@ void Spc::ADC_Imm() void Spc::ADDW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); - uint8_t lowCarry = (_tmp1 + _state.A) > 0xFF ? 1 : 0; - ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); - if(((_state.Y & 0x0F) + (msb & 0x0F) + lowCarry) & 0x10) { - SetFlags(SpcFlags::HalfCarry); - } + uint8_t lowCarry = (_tmp1 + _state.A) > 0xFF ? 1 : 0; + ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); + if (((_state.Y & 0x0F) + (msb & 0x0F) + lowCarry) & 0x10) + { + SetFlags(SpcFlags::HalfCarry); + } - uint16_t ya = (_state.Y << 8) | _state.A; - uint32_t result = ya + value; - if(result > 0xFFFF) { - SetFlags(SpcFlags::Carry); - } - SetZeroNegativeFlags16(result); + uint16_t ya = (_state.Y << 8) | _state.A; + uint32_t result = ya + value; + if (result > 0xFFFF) + { + SetFlags(SpcFlags::Carry); + } + SetZeroNegativeFlags16(result); - if(~(ya ^ value) & (ya ^ result) & 0x8000) { - SetFlags(SpcFlags::Overflow); - } + if (~(ya ^ value) & (ya ^ result) & 0x8000) + { + SetFlags(SpcFlags::Overflow); + } - _state.Y = result >> 8; - _state.A = (uint8_t)result; + _state.Y = result >> 8; + _state.A = (uint8_t)result; - EndOp(); + EndOp(); } } } void Spc::SBC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _tmp1 = (uint8_t)_operandA; - _tmp2 = Read(_operandB); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _tmp1 = (uint8_t)_operandA; + _tmp2 = Read(_operandB); + break; - case 1: - Write(_operandB, Sub((uint8_t)_tmp2, (uint8_t)_tmp1)); - EndOp(); - break; + case 1: + Write(_operandB, Sub((uint8_t)_tmp2, (uint8_t)_tmp1)); + EndOp(); + break; } } } void Spc::SBC_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = Sub(_state.A, GetByteValue()); EndOp(); } @@ -831,7 +1399,8 @@ void Spc::SBC_Acc() void Spc::SBC_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = Sub(_state.A, (uint8_t)_operandA); EndOp(); } @@ -839,49 +1408,59 @@ void Spc::SBC_Imm() void Spc::SUBW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); - uint16_t ya = (_state.Y << 8) | _state.A; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); + uint16_t ya = (_state.Y << 8) | _state.A; - uint32_t l = _state.A - _tmp1; - uint8_t carry = l > 0xFF ? 1 : 0; - uint32_t h = _state.Y - msb - carry; + uint32_t l = _state.A - _tmp1; + uint8_t carry = l > 0xFF ? 1 : 0; + uint32_t h = _state.Y - msb - carry; - ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); - if(h <= 0xFF) { - SetFlags(SpcFlags::Carry); - } + ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); + if (h <= 0xFF) + { + SetFlags(SpcFlags::Carry); + } - if((((_state.Y & 0x0F) - (msb & 0x0F) - carry) & 0x10) == 0) { - SetFlags(SpcFlags::HalfCarry); - } + if ((((_state.Y & 0x0F) - (msb & 0x0F) - carry) & 0x10) == 0) + { + SetFlags(SpcFlags::HalfCarry); + } - _state.Y = h; - _state.A = l; + _state.Y = h; + _state.A = l; - uint16_t result = (_state.Y << 8) | _state.A; + uint16_t result = (_state.Y << 8) | _state.A; - if((ya ^ value) & (ya ^ result) & 0x8000) { - SetFlags(SpcFlags::Overflow); - } + if ((ya ^ value) & (ya ^ result) & 0x8000) + { + SetFlags(SpcFlags::Overflow); + } - SetZeroNegativeFlags16(result); - EndOp(); - break; + SetZeroNegativeFlags16(result); + EndOp(); + break; } } } void Spc::Compare(uint8_t a, uint8_t b) { - if(a >= b) { + if (a >= b) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } @@ -891,17 +1470,23 @@ void Spc::Compare(uint8_t a, uint8_t b) void Spc::CMP() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Compare(Read(_operandB), (uint8_t)_operandA); break; - case 1: Idle(); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Compare(Read(_operandB), (uint8_t)_operandA); + break; + case 1: Idle(); + EndOp(); + break; } } } void Spc::CMP_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.A, GetByteValue()); EndOp(); } @@ -909,7 +1494,8 @@ void Spc::CMP_Acc() void Spc::CMP_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.A, (uint8_t)_operandA); EndOp(); } @@ -917,7 +1503,8 @@ void Spc::CMP_Imm() void Spc::CPX() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.X, GetByteValue()); EndOp(); } @@ -925,7 +1512,8 @@ void Spc::CPX() void Spc::CPX_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.X, (uint8_t)_operandA); EndOp(); } @@ -933,7 +1521,8 @@ void Spc::CPX_Imm() void Spc::CPY() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.Y, GetByteValue()); EndOp(); } @@ -941,7 +1530,8 @@ void Spc::CPY() void Spc::CPY_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.Y, (uint8_t)_operandA); EndOp(); } @@ -949,39 +1539,48 @@ void Spc::CPY_Imm() void Spc::CMPW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); - uint16_t ya = (_state.Y << 8) | _state.A; + uint16_t ya = (_state.Y << 8) | _state.A; - if(ya >= value) { - SetFlags(SpcFlags::Carry); - } else { - ClearFlags(SpcFlags::Carry); - } + if (ya >= value) + { + SetFlags(SpcFlags::Carry); + } + else + { + ClearFlags(SpcFlags::Carry); + } - uint16_t result = ya - value; - SetZeroNegativeFlags16(result); - EndOp(); - break; + uint16_t result = ya - value; + SetZeroNegativeFlags16(result); + EndOp(); + break; } } } void Spc::INC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) + 1; break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) + 1; + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1012,33 +1611,39 @@ void Spc::INY() void Spc::INCW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 + 1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 + 1); - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - uint8_t msb = Read(msbAddress); - uint16_t value = ((msb << 8) | _tmp1) + 1; - Write(msbAddress, value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + uint8_t msb = Read(msbAddress); + uint16_t value = ((msb << 8) | _tmp1) + 1; + Write(msbAddress, value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } void Spc::DEC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) - 1; break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) - 1; + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1069,160 +1674,206 @@ void Spc::DEY() void Spc::DECW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 - 1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 - 1); - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - uint8_t msb = Read(msbAddress); - uint16_t value = ((msb << 8) | _tmp1) - 1; - Write(msbAddress, value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + uint8_t msb = Read(msbAddress); + uint16_t value = ((msb << 8) | _tmp1) - 1; + Write(msbAddress, value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } void Spc::MUL() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: Idle(); break; - case 4: Idle(); break; - case 5: Idle(); break; - case 6: Idle(); break; - case 7: - Idle(); - uint16_t result = _state.Y * _state.A; - _state.Y = result >> 8; - _state.A = (uint8_t)result; - SetZeroNegativeFlags(_state.Y); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: Idle(); + break; + case 4: Idle(); + break; + case 5: Idle(); + break; + case 6: Idle(); + break; + case 7: + Idle(); + uint16_t result = _state.Y * _state.A; + _state.Y = result >> 8; + _state.A = (uint8_t)result; + SetZeroNegativeFlags(_state.Y); + EndOp(); + break; } } void Spc::DIV() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: Idle(); break; - case 4: Idle(); break; - case 5: Idle(); break; - case 6: Idle(); break; - case 7: Idle(); break; - case 8: Idle(); break; - case 9: Idle(); break; - case 11: - Idle(); - uint32_t ya = (_state.Y << 8) | _state.A; - uint32_t sub = _state.X << 9; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: Idle(); + break; + case 4: Idle(); + break; + case 5: Idle(); + break; + case 6: Idle(); + break; + case 7: Idle(); + break; + case 8: Idle(); + break; + case 9: Idle(); + break; + case 11: + Idle(); + uint32_t ya = (_state.Y << 8) | _state.A; + uint32_t sub = _state.X << 9; - for(int i = 0; i < 9; i++) { - if(ya & 0x10000) { - ya = ((ya << 1) | 0x01) & 0x1FFFF; - } else { - ya = (ya << 1) & 0x1FFFF; - } - - if(ya >= sub) { - ya ^= 0x01; - } - - if(ya & 0x01) { - ya = (ya - sub) & 0x1FFFF; - } + for (int i = 0; i < 9; i++) + { + if (ya & 0x10000) + { + ya = ((ya << 1) | 0x01) & 0x1FFFF; + } + else + { + ya = (ya << 1) & 0x1FFFF; } - - if((_state.Y & 0x0F) >= (_state.X & 0x0F)) { - SetFlags(SpcFlags::HalfCarry); - } else { - ClearFlags(SpcFlags::HalfCarry); + if (ya >= sub) + { + ya ^= 0x01; } - _state.A = (uint8_t)ya; - _state.Y = ya >> 9; - - if(ya & 0x100) { - SetFlags(SpcFlags::Overflow); - } else { - ClearFlags(SpcFlags::Overflow); + if (ya & 0x01) + { + ya = (ya - sub) & 0x1FFFF; } + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + + if ((_state.Y & 0x0F) >= (_state.X & 0x0F)) + { + SetFlags(SpcFlags::HalfCarry); + } + else + { + ClearFlags(SpcFlags::HalfCarry); + } + + _state.A = (uint8_t)ya; + _state.Y = ya >> 9; + + if (ya & 0x100) + { + SetFlags(SpcFlags::Overflow); + } + else + { + ClearFlags(SpcFlags::Overflow); + } + + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::DAA() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); - if(CheckFlag(SpcFlags::Carry) || _state.A > 0x99) { - _state.A += 0x60; - SetFlags(SpcFlags::Carry); - } + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); + if (CheckFlag(SpcFlags::Carry) || _state.A > 0x99) + { + _state.A += 0x60; + SetFlags(SpcFlags::Carry); + } - if(CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) { - _state.A += 6; - } + if (CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) + { + _state.A += 6; + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::DAS() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); - if(!CheckFlag(SpcFlags::Carry) || _state.A > 0x99) { - _state.A -= 0x60; - ClearFlags(SpcFlags::Carry); - } + if (!CheckFlag(SpcFlags::Carry) || _state.A > 0x99) + { + _state.A -= 0x60; + ClearFlags(SpcFlags::Carry); + } - if(!CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) { - _state.A -= 6; - } + if (!CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) + { + _state.A -= 6; + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::AND() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA & Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA & Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::AND_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A &= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1231,7 +1882,8 @@ void Spc::AND_Acc() void Spc::AND_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A &= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1240,21 +1892,25 @@ void Spc::AND_Imm() void Spc::OR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA | Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA | Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::OR_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A |= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1263,7 +1919,8 @@ void Spc::OR_Acc() void Spc::OR_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A |= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1272,21 +1929,25 @@ void Spc::OR_Imm() void Spc::EOR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA ^ Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA ^ Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::EOR_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A ^= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1295,7 +1956,8 @@ void Spc::EOR_Acc() void Spc::EOR_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A ^= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1309,9 +1971,11 @@ void Spc::SetCarry(uint8_t carry) void Spc::OR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry |= (Read(_operandA) >> _operandB) & 0x01; @@ -1319,19 +1983,21 @@ void Spc::OR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::NOR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry |= ~((Read(_operandA) >> _operandB)) & 0x01; @@ -1339,17 +2005,18 @@ void Spc::NOR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::AND1() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = _state.PS & SpcFlags::Carry; carry &= (Read(_operandA) >> _operandB) & 0x01; SetCarry(carry); @@ -1359,7 +2026,8 @@ void Spc::AND1() void Spc::NAND1() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = _state.PS & SpcFlags::Carry; carry &= ~((Read(_operandA) >> _operandB)) & 0x01; SetCarry(carry); @@ -1369,9 +2037,11 @@ void Spc::NAND1() void Spc::EOR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry ^= (Read(_operandA) >> _operandB) & 0x01; @@ -1379,47 +2049,55 @@ void Spc::EOR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::NOT1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - uint8_t mask = (1 << _operandB); - Write(_operandA, _tmp1 ^ mask); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + uint8_t mask = (1 << _operandB); + Write(_operandA, _tmp1 ^ mask); + EndOp(); + break; } } } void Spc::STC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t mask = (1 << _operandB); - uint8_t carry = (_state.PS & SpcFlags::Carry) << _operandB; - Write(_operandA, (_tmp1 & ~mask) | carry); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t mask = (1 << _operandB); + uint8_t carry = (_state.PS & SpcFlags::Carry) << _operandB; + Write(_operandA, (_tmp1 & ~mask) | carry); + EndOp(); + break; } } } void Spc::LDC() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = (Read(_operandA) >> _operandB) & 0x01; SetCarry(carry); EndOp(); @@ -1429,9 +2107,12 @@ void Spc::LDC() uint8_t Spc::ShiftLeft(uint8_t value) { uint8_t result = value << 1; - if(value & (1 << 7)) { + if (value & (1 << 7)) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1441,9 +2122,12 @@ uint8_t Spc::ShiftLeft(uint8_t value) uint8_t Spc::RollLeft(uint8_t value) { uint8_t result = value << 1 | (_state.PS & SpcFlags::Carry); - if(value & (1 << 7)) { + if (value & (1 << 7)) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1453,9 +2137,12 @@ uint8_t Spc::RollLeft(uint8_t value) uint8_t Spc::ShiftRight(uint8_t value) { uint8_t result = value >> 1; - if(value & 0x01) { + if (value & 0x01) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1465,9 +2152,12 @@ uint8_t Spc::ShiftRight(uint8_t value) uint8_t Spc::RollRight(uint8_t value) { uint8_t result = value >> 1 | ((_state.PS & 0x01) << 7); - if(value & 0x01) { + if (value & 0x01) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1476,13 +2166,16 @@ uint8_t Spc::RollRight(uint8_t value) void Spc::ASL() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = ShiftLeft(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ShiftLeft(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1496,13 +2189,16 @@ void Spc::ASL_Acc() void Spc::LSR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = ShiftRight(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ShiftRight(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1516,13 +2212,16 @@ void Spc::LSR_Acc() void Spc::ROL() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = RollLeft(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = RollLeft(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1536,13 +2235,16 @@ void Spc::ROL_Acc() void Spc::ROR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = RollRight(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = RollRight(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1556,45 +2258,56 @@ void Spc::ROR_Acc() void Spc::XCN() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: - Idle(); - _state.A = (_state.A >> 4) | (_state.A << 4); - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: + Idle(); + _state.A = (_state.A >> 4) | (_state.A << 4); + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::Branch() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); - int8_t offset = (int8_t)_operandA; - _state.PC = _state.PC + offset; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); + int8_t offset = (int8_t)_operandA; + _state.PC = _state.PC + offset; + EndOp(); + break; } } void Spc::BRA() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Branch(); } } void Spc::BEQ() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Zero)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Zero)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1602,10 +2315,14 @@ void Spc::BEQ() void Spc::BNE() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Zero)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Zero)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1613,10 +2330,14 @@ void Spc::BNE() void Spc::BCS() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Carry)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Carry)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1624,10 +2345,14 @@ void Spc::BCS() void Spc::BCC() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Carry)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Carry)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1635,10 +2360,14 @@ void Spc::BCC() void Spc::BVS() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Overflow)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Overflow)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1646,10 +2375,14 @@ void Spc::BVS() void Spc::BVC() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Overflow)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Overflow)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1657,10 +2390,14 @@ void Spc::BVC() void Spc::BMI() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Negative)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Negative)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1668,163 +2405,203 @@ void Spc::BMI() void Spc::BPL() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Negative)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Negative)) + { Branch(); - } else { + } + else + { EndOp(); } } } -template +template void Spc::SET1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 | (1 << bit)); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 | (1 << bit)); + EndOp(); + break; } } } -template +template void Spc::CLR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 & ~(1 << bit)); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 & ~(1 << bit)); + EndOp(); + break; } } } -template +template void Spc::BBS() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(!(_tmp1 & (1 << bit))) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (!(_tmp1 & (1 << bit))) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } -template +template void Spc::BBC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(_tmp1 & (1 << bit)) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (_tmp1 & (1 << bit)) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::CBNE() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(_state.A == _tmp1) { - EndOp(); - } - break; - - case 3: Idle(); break; - - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (_state.A == _tmp1) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::DBNZ() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) - 1; break; - case 1: Write(_operandA, (uint8_t)_tmp1); break; - case 2: - _tmp2 = ReadOperandByte(); - if(!_tmp1) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) - 1; + break; + case 1: Write(_operandA, (uint8_t)_tmp1); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (!_tmp1) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::DBNZ_Y() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: - _state.Y--; - _tmp2 = ReadOperandByte(); - if(!_state.Y) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: + _state.Y--; + _tmp2 = ReadOperandByte(); + if (!_state.Y) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } void Spc::JMP() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.PC = _operandA; EndOp(); } @@ -1832,17 +2609,22 @@ void Spc::JMP() void Spc::NOTC() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - Idle(); - if(CheckFlag(SpcFlags::Carry)) { - ClearFlags(SpcFlags::Carry); - } else { - SetFlags(SpcFlags::Carry); - } - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + Idle(); + if (CheckFlag(SpcFlags::Carry)) + { + ClearFlags(SpcFlags::Carry); + } + else + { + SetFlags(SpcFlags::Carry); + } + EndOp(); + break; } } @@ -1883,176 +2665,228 @@ void Spc::SETP() void Spc::EI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - SetFlags(SpcFlags::IrqEnable); - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + SetFlags(SpcFlags::IrqEnable); + Idle(); + EndOp(); + break; } } void Spc::DI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - ClearFlags(SpcFlags::IrqEnable); - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + ClearFlags(SpcFlags::IrqEnable); + Idle(); + EndOp(); + break; } } void Spc::TSET1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: DummyRead(_operandA); break; - case 2: - Write(_operandA, _tmp1 | _state.A); - SetZeroNegativeFlags(_state.A - _tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: DummyRead(_operandA); + break; + case 2: + Write(_operandA, _tmp1 | _state.A); + SetZeroNegativeFlags(_state.A - _tmp1); + EndOp(); + break; } } } void Spc::TCLR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: DummyRead(_operandA); break; - case 2: - Write(_operandA, _tmp1 & ~_state.A); - SetZeroNegativeFlags(_state.A - _tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: DummyRead(_operandA); + break; + case 2: + Write(_operandA, _tmp1 & ~_state.A); + SetZeroNegativeFlags(_state.A - _tmp1); + EndOp(); + break; } } } -template +template void Spc::TCALL() { constexpr uint16_t vectorAddr = 0xFFDE - (offset * 2); - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Push(_state.PC >> 8); break; - case 3: Push((uint8_t)_state.PC); break; - case 4: Idle(); break; - case 5: _tmp1 = Read(vectorAddr); break; - case 6: - _state.PC = (Read(vectorAddr + 1) << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Push(_state.PC >> 8); + break; + case 3: Push((uint8_t)_state.PC); + break; + case 4: Idle(); + break; + case 5: _tmp1 = Read(vectorAddr); + break; + case 6: + _state.PC = (Read(vectorAddr + 1) << 8) | _tmp1; + EndOp(); + break; } } void Spc::PCALL() { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: Idle(); break; - case 2: Push(_state.PC >> 8); break; - case 3: Push((uint8_t)_state.PC); break; - case 4: - Idle(); - _state.PC = 0xFF00 | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: Idle(); + break; + case 2: Push(_state.PC >> 8); + break; + case 3: Push((uint8_t)_state.PC); + break; + case 4: + Idle(); + _state.PC = 0xFF00 | _tmp1; + EndOp(); + break; } } void Spc::JSR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: Push(_state.PC >> 8); break; - case 2: Push((uint8_t)_state.PC); break; - case 3: Idle(); break; - case 4: - Idle(); - _state.PC = _operandA; - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: Push(_state.PC >> 8); + break; + case 2: Push((uint8_t)_state.PC); + break; + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC = _operandA; + EndOp(); + break; } } } void Spc::RTS() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: _tmp1 = Pop(); break; - case 3: - _state.PC = (Pop() << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: _tmp1 = Pop(); + break; + case 3: + _state.PC = (Pop() << 8) | _tmp1; + EndOp(); + break; } } void Spc::RTI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: _state.PS = Pop(); break; - case 3: _tmp1 = Pop(); break; - case 4: - _state.PC = (Pop() << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: _state.PS = Pop(); + break; + case 3: _tmp1 = Pop(); + break; + case 4: + _state.PC = (Pop() << 8) | _tmp1; + EndOp(); + break; } } void Spc::BRK() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: Push(_state.PC >> 8); break; - case 2: Push((uint8_t)_state.PC); break; - case 3: Push(_state.PS); break; - case 4: Idle(); break; - case 5: _tmp1 = Read(0xFFDE); break; - case 6: - uint8_t msb = Read(0xFFDF); - _state.PC = (msb << 8) | _tmp1; + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: Push(_state.PC >> 8); + break; + case 2: Push((uint8_t)_state.PC); + break; + case 3: Push(_state.PS); + break; + case 4: Idle(); + break; + case 5: _tmp1 = Read(0xFFDE); + break; + case 6: + uint8_t msb = Read(0xFFDF); + _state.PC = (msb << 8) | _tmp1; - SetFlags(SpcFlags::Break); - ClearFlags(SpcFlags::IrqEnable); - EndOp(); - break; + SetFlags(SpcFlags::Break); + ClearFlags(SpcFlags::IrqEnable); + EndOp(); + break; } } void Spc::PushOperation(uint8_t value) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Push(value); break; - case 2: - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Push(value); + break; + case 2: + Idle(); + EndOp(); + break; } } -void Spc::PullOperation(uint8_t &dst) +void Spc::PullOperation(uint8_t& dst) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: - dst = Pop(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: + dst = Pop(); + EndOp(); + break; } } diff --git a/Core/Spc.cpp b/Core/Spc.cpp index 06126ae..6dda552 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -24,9 +24,9 @@ Spc::Spc(Console* console) _console->GetSettings()->InitializeRam(_ram, Spc::SpcRamSize); _dsp.reset(new SPC_DSP()); - #ifndef DUMMYSPC +#ifndef DUMMYSPC _dsp->init(this, _console->GetSettings().get(), _ram); - #endif +#endif _dsp->reset(); _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); @@ -76,7 +76,7 @@ void Spc::Reset() _state.RomEnabled = true; _state.Cycle = 0; _state.PC = ReadWord(Spc::ResetVector); - + _opCode = 0; _opStep = SpcOpStep::ReadOpCode; _opSubStep = 0; @@ -93,11 +93,15 @@ void Spc::Reset() void Spc::SetSpcState(bool enabled) { //Used by overclocking logic to disable SPC during the extra scanlines added to the PPU - if(_enabled != enabled) { - if(enabled) { + if (_enabled != enabled) + { + if (enabled) + { //When re-enabling, adjust the cycle counter to prevent running extra cycles UpdateClockRatio(); - } else { + } + else + { //Catch up SPC before disabling it Run(); } @@ -113,7 +117,8 @@ void Spc::UpdateClockRatio() //This can happen due to overclocking (which disables the SPC for some scanlines) or if the SPC's //internal sample rate is changed between versions (e.g 32000hz -> 32040hz) uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - if(std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) { + if (std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) + { _state.Cycle = targetCycle; } } @@ -135,14 +140,17 @@ void Spc::DummyRead(uint16_t addr) void Spc::IncCycleCount(int32_t addr) { - static constexpr uint8_t cpuWait[4] = { 2, 4, 10, 20 }; - static constexpr uint8_t timerMultiplier[4] = { 2, 4, 8, 16 }; + static constexpr uint8_t cpuWait[4] = {2, 4, 10, 20}; + static constexpr uint8_t timerMultiplier[4] = {2, 4, 8, 16}; uint8_t speedSelect; - if(addr < 0 || ((addr & 0xFFF0) == 0x00F0) || (addr >= 0xFFC0 && _state.RomEnabled)) { + if (addr < 0 || ((addr & 0xFFF0) == 0x00F0) || (addr >= 0xFFC0 && _state.RomEnabled)) + { //Use internal speed (bits 4-5) for idle cycles, register access or IPL rom access speedSelect = _state.InternalSpeed; - } else { + } + else + { speedSelect = _state.ExternalSpeed; } @@ -159,34 +167,36 @@ void Spc::IncCycleCount(int32_t addr) uint8_t Spc::DebugRead(uint16_t addr) { - if(addr >= 0xFFC0 && _state.RomEnabled) { + if (addr >= 0xFFC0 && _state.RomEnabled) + { return _spcBios[addr & 0x3F]; } - switch(addr) { - case 0xF0: return 0; - case 0xF1: return 0; + switch (addr) + { + case 0xF0: return 0; + case 0xF1: return 0; - case 0xF2: return _state.DspReg; - case 0xF3: return _dsp->read(_state.DspReg & 0x7F); + case 0xF2: return _state.DspReg; + case 0xF3: return _dsp->read(_state.DspReg & 0x7F); - case 0xF4: return _state.CpuRegs[0]; - case 0xF5: return _state.CpuRegs[1]; - case 0xF6: return _state.CpuRegs[2]; - case 0xF7: return _state.CpuRegs[3]; + case 0xF4: return _state.CpuRegs[0]; + case 0xF5: return _state.CpuRegs[1]; + case 0xF6: return _state.CpuRegs[2]; + case 0xF7: return _state.CpuRegs[3]; - case 0xF8: return _state.RamReg[0]; - case 0xF9: return _state.RamReg[1]; + case 0xF8: return _state.RamReg[0]; + case 0xF9: return _state.RamReg[1]; - case 0xFA: return 0; - case 0xFB: return 0; - case 0xFC: return 0; + case 0xFA: return 0; + case 0xFB: return 0; + case 0xFC: return 0; - case 0xFD: return _state.Timer0.DebugRead(); - case 0xFE: return _state.Timer1.DebugRead(); - case 0xFF: return _state.Timer2.DebugRead(); + case 0xFD: return _state.Timer0.DebugRead(); + case 0xFE: return _state.Timer1.DebugRead(); + case 0xFF: return _state.Timer2.DebugRead(); - default: return _ram[addr]; + default: return _ram[addr]; } } @@ -200,45 +210,65 @@ uint8_t Spc::Read(uint16_t addr, MemoryOperationType type) IncCycleCount(addr); uint8_t value; - if(addr >= 0xFFC0 && _state.RomEnabled) { + if (addr >= 0xFFC0 && _state.RomEnabled) + { value = _spcBios[addr & 0x3F]; - } else { - switch(addr) { - case 0xF0: value = 0; break; - case 0xF1: value = 0; break; + } + else + { + switch (addr) + { + case 0xF0: value = 0; + break; + case 0xF1: value = 0; + break; - case 0xF2: value = _state.DspReg; break; - case 0xF3: - #ifndef DUMMYSPC + case 0xF2: value = _state.DspReg; + break; + case 0xF3: +#ifndef DUMMYSPC value = _dsp->read(_state.DspReg & 0x7F); - #else - value = 0; - #endif - break; +#else + value = 0; +#endif + break; - case 0xF4: value = _state.CpuRegs[0]; break; - case 0xF5: value = _state.CpuRegs[1]; break; - case 0xF6: value = _state.CpuRegs[2]; break; - case 0xF7: value = _state.CpuRegs[3]; break; + case 0xF4: value = _state.CpuRegs[0]; + break; + case 0xF5: value = _state.CpuRegs[1]; + break; + case 0xF6: value = _state.CpuRegs[2]; + break; + case 0xF7: value = _state.CpuRegs[3]; + break; - case 0xF8: value = _state.RamReg[0]; break; - case 0xF9: value = _state.RamReg[1]; break; + case 0xF8: value = _state.RamReg[0]; + break; + case 0xF9: value = _state.RamReg[1]; + break; - case 0xFA: value = 0; break; - case 0xFB: value = 0; break; - case 0xFC: value = 0; break; + case 0xFA: value = 0; + break; + case 0xFB: value = 0; + break; + case 0xFC: value = 0; + break; - case 0xFD: value = _state.Timer0.GetOutput(); break; - case 0xFE: value = _state.Timer1.GetOutput(); break; - case 0xFF: value = _state.Timer2.GetOutput(); break; + case 0xFD: value = _state.Timer0.GetOutput(); + break; + case 0xFE: value = _state.Timer1.GetOutput(); + break; + case 0xFF: value = _state.Timer2.GetOutput(); + break; - default: value = _ram[addr]; break; + default: value = _ram[addr]; + break; } } #ifndef DUMMYSPC _console->ProcessMemoryRead(addr, value, type); -#else +#else LogRead(addr, value); #endif @@ -346,24 +376,29 @@ void Spc::DspWriteRam(uint16_t addr, uint8_t value) void Spc::Run() { - if(!_enabled || _state.StopState != CpuStopState::Running) { + if (!_enabled || _state.StopState != CpuStopState::Running) + { //STOP or SLEEP were executed - execution is stopped forever. return; } uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - while(_state.Cycle < targetCycle) { + while (_state.Cycle < targetCycle) + { ProcessCycle(); } } void Spc::ProcessCycle() { - if(_opStep == SpcOpStep::ReadOpCode) { + if (_opStep == SpcOpStep::ReadOpCode) + { _opCode = GetOpCode(); _opStep = SpcOpStep::Addressing; _opSubStep = 0; - } else { + } + else + { Exec(); } } @@ -375,7 +410,8 @@ void Spc::ProcessEndFrame() UpdateClockRatio(); int sampleCount = _dsp->sample_count(); - if(sampleCount != 0) { + if (sampleCount != 0) + { _console->GetSoundMixer()->PlayAudioBuffer(_soundBuffer, sampleCount / 2, Spc::SpcSampleRate); } _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); @@ -400,20 +436,26 @@ bool Spc::IsMuted() AddressInfo Spc::GetAbsoluteAddress(uint16_t addr) { - if(addr < 0xFFC0 || !_state.RomEnabled) { - return AddressInfo { addr, SnesMemoryType::SpcRam }; + if (addr < 0xFFC0 || !_state.RomEnabled) + { + return AddressInfo{addr, SnesMemoryType::SpcRam}; } - return AddressInfo { addr & 0x3F, SnesMemoryType::SpcRom }; + return AddressInfo{addr & 0x3F, SnesMemoryType::SpcRom}; } -int Spc::GetRelativeAddress(AddressInfo &absAddress) +int Spc::GetRelativeAddress(AddressInfo& absAddress) { - if(absAddress.Type == SnesMemoryType::SpcRom) { - if(_state.RomEnabled) { + if (absAddress.Type == SnesMemoryType::SpcRom) + { + if (_state.RomEnabled) + { return 0xFFC0 | (absAddress.Address & 0x3F); } - } else { - if(absAddress.Address < 0xFFC0 || !_state.RomEnabled) { + } + else + { + if (absAddress.Address < 0xFFC0 || !_state.RomEnabled) + { return absAddress.Address; } } @@ -430,7 +472,7 @@ uint8_t* Spc::GetSpcRom() return _spcBios; } -void Spc::Serialize(Serializer &s) +void Spc::Serialize(Serializer& s) { s.Stream(_state.A, _state.Cycle, _state.PC, _state.PS, _state.SP, _state.X, _state.Y); s.Stream(_state.CpuRegs[0], _state.CpuRegs[1], _state.CpuRegs[2], _state.CpuRegs[3]); @@ -443,26 +485,31 @@ void Spc::Serialize(Serializer &s) _state.Timer1.Serialize(s); _state.Timer2.Serialize(s); - ArrayInfo ram { _ram, Spc::SpcRamSize }; + ArrayInfo ram{_ram, Spc::SpcRamSize}; s.Stream(ram); uint8_t dspState[SPC_DSP::state_size]; memset(dspState, 0, SPC_DSP::state_size); - if(s.IsSaving()) { - uint8_t *out = dspState; - _dsp->copy_state(&out, [](uint8_t** output, void* in, size_t size) { + if (s.IsSaving()) + { + uint8_t* out = dspState; + _dsp->copy_state(&out, [](uint8_t** output, void* in, size_t size) + { memcpy(*output, in, size); *output += size; }); s.StreamArray(dspState, SPC_DSP::state_size); - } else { + } + else + { s.StreamArray(dspState, SPC_DSP::state_size); UpdateClockRatio(); - uint8_t *in = dspState; - _dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) { + uint8_t* in = dspState; + _dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) + { memcpy(output, *input, size); *input += size; }); @@ -512,9 +559,12 @@ bool Spc::CheckFlag(uint8_t flag) void Spc::SetZeroNegativeFlags(uint8_t value) { ClearFlags(SpcFlags::Zero | SpcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(SpcFlags::Zero); - } else if(value & 0x80) { + } + else if (value & 0x80) + { SetFlags(SpcFlags::Negative); } } @@ -522,9 +572,12 @@ void Spc::SetZeroNegativeFlags(uint8_t value) void Spc::SetZeroNegativeFlags16(uint16_t value) { ClearFlags(SpcFlags::Zero | SpcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(SpcFlags::Zero); - } else if(value & 0x8000) { + } + else if (value & 0x8000) + { SetFlags(SpcFlags::Negative); } } @@ -571,7 +624,7 @@ void Spc::LoadSpcFile(SpcFileData* data) _state.CpuRegs[1] = data->CpuRegs[1]; _state.CpuRegs[2] = data->CpuRegs[2]; _state.CpuRegs[3] = data->CpuRegs[3]; - + _state.RamReg[0] = data->RamRegs[0]; _state.RamReg[1] = data->RamRegs[1]; @@ -589,28 +642,34 @@ void Spc::SetReg(SpcRegister reg, uint16_t value) switch (reg) { case SpcRegister::SpcRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case SpcRegister::SpcRegA: - { - _state.A = value & 0xFF; - } break; + { + _state.A = value & 0xFF; + } + break; case SpcRegister::SpcRegX: - { - _state.X = value & 0xFF; - } break; + { + _state.X = value & 0xFF; + } + break; case SpcRegister::SpcRegY: - { - _state.Y = value & 0xFF; - } break; + { + _state.Y = value & 0xFF; + } + break; case SpcRegister::SpcRegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; case SpcRegister::SpcRegPS: - { - _state.PS = value & 0xFF; - } break; + { + _state.PS = value & 0xFF; + } + break; } } diff --git a/Core/Spc.h b/Core/Spc.h index 1d745dc..f572d69 100644 --- a/Core/Spc.h +++ b/Core/Spc.h @@ -49,7 +49,7 @@ private: SpcState _state; uint8_t* _ram; - uint8_t _spcBios[64] { + uint8_t _spcBios[64]{ 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, @@ -60,7 +60,7 @@ private: 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF }; - int16_t *_soundBuffer; + int16_t* _soundBuffer; //Store operations void STA(); @@ -81,7 +81,7 @@ private: void LDW(); //Transfer - void Transfer(uint8_t & dst, uint8_t src); + void Transfer(uint8_t& dst, uint8_t src); void TXA(); void TYA(); void TAX(); @@ -203,10 +203,14 @@ private: void TSET1(); void TCLR1(); - template void SET1(); - template void CLR1(); - template void BBS(); - template void BBC(); + template + void SET1(); + template + void CLR1(); + template + void BBS(); + template + void BBC(); //Subroutine operations void PCALL(); @@ -215,11 +219,12 @@ private: void BRK(); void RTI(); - template void TCALL(); + template + void TCALL(); //Stack operations void PushOperation(uint8_t value); - void PullOperation(uint8_t & dst); + void PullOperation(uint8_t& dst); void PHA(); void PHX(); @@ -235,7 +240,7 @@ private: void NOP(); void SLEEP(); void STOP(); - + void Idle(); void DummyRead(); void DummyRead(uint16_t addr); @@ -281,7 +286,7 @@ private: void EndAddr(); void ProcessCycle(); void Exec(); - + void UpdateClockRatio(); public: @@ -309,14 +314,14 @@ public: bool IsMuted(); AddressInfo GetAbsoluteAddress(uint16_t addr); - int GetRelativeAddress(AddressInfo & absAddress); + int GetRelativeAddress(AddressInfo& absAddress); uint8_t* GetSpcRam(); uint8_t* GetSpcRom(); void LoadSpcFile(SpcFileData* spcData); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(SpcRegister reg, uint16_t value); @@ -348,4 +353,4 @@ public: #endif }; -#endif \ No newline at end of file +#endif diff --git a/Core/Spc7110.cpp b/Core/Spc7110.cpp index c7dd233..74039d9 100644 --- a/Core/Spc7110.cpp +++ b/Core/Spc7110.cpp @@ -39,10 +39,13 @@ Spc7110::Spc7110(Console* console, bool useRtc) : BaseCoprocessor(SnesMemoryType bool enableStrictBoardMappings = console->GetSettings()->GetEmulationConfig().EnableStrictBoardMappings; uint32_t romSize = _cart->DebugGetPrgRomSize(); - if(!enableStrictBoardMappings && _cart->DebugGetPrgRomSize() >= 0x600000) { + if (!enableStrictBoardMappings && _cart->DebugGetPrgRomSize() >= 0x600000) + { mappings->RegisterHandler(0x40, 0x4F, 0x0000, 0xFFFF, prgRomHandlers, 0, 0x600); _realDataRomSize = romSize - 0x200000; - } else { + } + else + { _realDataRomSize = romSize - 0x100000; } mappings->RegisterHandler(0xC0, 0xCF, 0x0000, 0xFFFF, prgRomHandlers); @@ -52,212 +55,258 @@ Spc7110::Spc7110(Console* console, bool useRtc) : BaseCoprocessor(SnesMemoryType void Spc7110::Serialize(Serializer& s) { - ArrayInfo decompBuffer = { _decompBuffer, 32 }; - ArrayInfo dataRomBanks = { _dataRomBanks, 3 }; + ArrayInfo decompBuffer = {_decompBuffer, 32}; + ArrayInfo dataRomBanks = {_dataRomBanks, 3}; s.Stream( - _directoryBase, _directoryIndex, _targetOffset, _dataLengthCounter, _skipBytes, _decompFlags, _decompMode, _srcAddress, _decompOffset, _decompStatus, - decompBuffer, _dividend = 0, _multiplier, _divisor, _multDivResult, _remainder, _aluState, _aluFlags, _sramEnabled, dataRomBanks, _dataRomSize, _readBase, + _directoryBase, _directoryIndex, _targetOffset, _dataLengthCounter, _skipBytes, _decompFlags, _decompMode, + _srcAddress, _decompOffset, _decompStatus, + decompBuffer, _dividend = 0, _multiplier, _divisor, _multDivResult, _remainder, _aluState, _aluFlags, + _sramEnabled, dataRomBanks, _dataRomSize, _readBase, _readOffset, _readStep, _readMode, _readBuffer ); s.Stream(_decomp.get()); - if(_rtc) { + if (_rtc) + { s.Stream(_rtc.get()); } } uint8_t Spc7110::Read(uint32_t addr) { - if((addr & 0xFF0000) == 0x500000) { + if ((addr & 0xFF0000) == 0x500000) + { addr = 0x4800; - } else if((addr & 0xFF0000) == 0x580000) { + } + else if ((addr & 0xFF0000) == 0x580000) + { addr = 0x4808; } - switch(addr & 0xFFFF) { + switch (addr & 0xFFFF) + { //Decompression - case 0x4800: - _dataLengthCounter--; - return ReadDecompressedByte(); + case 0x4800: + _dataLengthCounter--; + return ReadDecompressedByte(); - case 0x4801: return (_directoryBase) & 0xFF; - case 0x4802: return (_directoryBase >> 8) & 0xFF; - case 0x4803: return (_directoryBase >> 16) & 0xFF; - case 0x4804: return _directoryIndex; - case 0x4805: return (_targetOffset) & 0xFF; - case 0x4806: return (_targetOffset >> 8) & 0xFF; - case 0x4807: return _skipBytes; - case 0x4808: return 0; - case 0x4809: return (_dataLengthCounter & 0xFF); - case 0x480A: return (_dataLengthCounter >> 8) & 0xFF; - case 0x480B: return _decompFlags; - case 0x480C: return _decompStatus; + case 0x4801: return (_directoryBase) & 0xFF; + case 0x4802: return (_directoryBase >> 8) & 0xFF; + case 0x4803: return (_directoryBase >> 16) & 0xFF; + case 0x4804: return _directoryIndex; + case 0x4805: return (_targetOffset) & 0xFF; + case 0x4806: return (_targetOffset >> 8) & 0xFF; + case 0x4807: return _skipBytes; + case 0x4808: return 0; + case 0x4809: return (_dataLengthCounter & 0xFF); + case 0x480A: return (_dataLengthCounter >> 8) & 0xFF; + case 0x480B: return _decompFlags; + case 0x480C: return _decompStatus; //Data read - case 0x4810: { + case 0x4810: + { uint8_t value = _readBuffer; IncrementPosition4810(); return value; } - case 0x4811: return _readBase & 0xFF; - case 0x4812: return (_readBase >> 8) & 0xFF; - case 0x4813: return (_readBase >> 16) & 0xFF; - case 0x4814: return _readOffset & 0xFF; - case 0x4815: return (_readOffset >> 8) & 0xFF; - case 0x4816: return _readStep & 0xFF; - case 0x4817: return (_readStep >> 8) & 0xFF; - case 0x4818: return _readMode; + case 0x4811: return _readBase & 0xFF; + case 0x4812: return (_readBase >> 8) & 0xFF; + case 0x4813: return (_readBase >> 16) & 0xFF; + case 0x4814: return _readOffset & 0xFF; + case 0x4815: return (_readOffset >> 8) & 0xFF; + case 0x4816: return _readStep & 0xFF; + case 0x4817: return (_readStep >> 8) & 0xFF; + case 0x4818: return _readMode; - case 0x481A: - if((_readMode & 0x60) == 0x60) { - IncrementPosition(); - } - return 0; + case 0x481A: + if ((_readMode & 0x60) == 0x60) + { + IncrementPosition(); + } + return 0; //ALU - case 0x4820: return _dividend & 0xFF; - case 0x4821: return (_dividend >> 8) & 0xFF; - case 0x4822: return (_dividend >> 16) & 0xFF; - case 0x4823: return (_dividend >> 24) & 0xFF; - case 0x4824: return _multiplier & 0xFF; - case 0x4825: return (_multiplier >> 8) & 0xFF; - case 0x4826: return _divisor & 0xFF; - case 0x4827: return (_divisor >> 8) & 0xFF; - case 0x4828: return _multDivResult & 0xFF; - case 0x4829: return (_multDivResult >> 8) & 0xFF; - case 0x482A: return (_multDivResult >> 16) & 0xFF; - case 0x482B: return (_multDivResult >> 24) & 0xFF; - case 0x482C: return _remainder & 0xFF; - case 0x482D: return (_remainder >> 8) & 0xFF; - case 0x482E: return _aluFlags; - case 0x482F: return _aluState; + case 0x4820: return _dividend & 0xFF; + case 0x4821: return (_dividend >> 8) & 0xFF; + case 0x4822: return (_dividend >> 16) & 0xFF; + case 0x4823: return (_dividend >> 24) & 0xFF; + case 0x4824: return _multiplier & 0xFF; + case 0x4825: return (_multiplier >> 8) & 0xFF; + case 0x4826: return _divisor & 0xFF; + case 0x4827: return (_divisor >> 8) & 0xFF; + case 0x4828: return _multDivResult & 0xFF; + case 0x4829: return (_multDivResult >> 8) & 0xFF; + case 0x482A: return (_multDivResult >> 16) & 0xFF; + case 0x482B: return (_multDivResult >> 24) & 0xFF; + case 0x482C: return _remainder & 0xFF; + case 0x482D: return (_remainder >> 8) & 0xFF; + case 0x482E: return _aluFlags; + case 0x482F: return _aluState; - case 0x4830: return _sramEnabled; - case 0x4831: return _dataRomBanks[0]; - case 0x4832: return _dataRomBanks[1]; - case 0x4833: return _dataRomBanks[2]; - case 0x4834: return _dataRomSize; + case 0x4830: return _sramEnabled; + case 0x4831: return _dataRomBanks[0]; + case 0x4832: return _dataRomBanks[1]; + case 0x4833: return _dataRomBanks[2]; + case 0x4834: return _dataRomSize; - case 0x4840: - case 0x4841: - case 0x4842: - return _rtc ? _rtc->Read(addr) : 0; + case 0x4840: + case 0x4841: + case 0x4842: + return _rtc ? _rtc->Read(addr) : 0; - default: - if((addr & 0xFFFF) >= 0x4800) { - LogDebug("[Debug] Missing read handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); - } - return _cpuRegisterHandler->Read(addr); + default: + if ((addr & 0xFFFF) >= 0x4800) + { + LogDebug("[Debug] Missing read handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); + } + return _cpuRegisterHandler->Read(addr); } } void Spc7110::Write(uint32_t addr, uint8_t value) { - if((addr & 0xFF0000) == 0x500000) { + if ((addr & 0xFF0000) == 0x500000) + { addr = 0x4800; - } else if((addr & 0xFF0000) == 0x580000) { + } + else if ((addr & 0xFF0000) == 0x580000) + { addr = 0x4808; } - switch(addr & 0xFFFF) { + switch (addr & 0xFFFF) + { //Data ROM Decompression (4800-480C) - case 0x4801: _directoryBase = (_directoryBase & 0xFFFF00) | value; break; - case 0x4802: _directoryBase = (_directoryBase & 0xFF00FF) | (value << 8); break; - case 0x4803: _directoryBase = (_directoryBase & 0x00FFFF) | (value << 16); break; - case 0x4804: - _directoryIndex = value; - LoadEntryHeader(); - break; + case 0x4801: _directoryBase = (_directoryBase & 0xFFFF00) | value; + break; + case 0x4802: _directoryBase = (_directoryBase & 0xFF00FF) | (value << 8); + break; + case 0x4803: _directoryBase = (_directoryBase & 0x00FFFF) | (value << 16); + break; + case 0x4804: + _directoryIndex = value; + LoadEntryHeader(); + break; - case 0x4805: _targetOffset = (_targetOffset & 0xFF00) | value; break; - case 0x4806: - _targetOffset = (_targetOffset & 0x00FF) | (value << 8); - BeginDecompression(); - break; + case 0x4805: _targetOffset = (_targetOffset & 0xFF00) | value; + break; + case 0x4806: + _targetOffset = (_targetOffset & 0x00FF) | (value << 8); + BeginDecompression(); + break; - case 0x4807: _skipBytes = value; break; - case 0x4808: break; + case 0x4807: _skipBytes = value; + break; + case 0x4808: break; - case 0x4809: _dataLengthCounter = (_dataLengthCounter & 0xFF00) | value; break; - case 0x480A: _dataLengthCounter = (_dataLengthCounter & 0x00FF) | (value << 8); break; - case 0x480B: _decompFlags = value & 0x03; break; + case 0x4809: _dataLengthCounter = (_dataLengthCounter & 0xFF00) | value; + break; + case 0x480A: _dataLengthCounter = (_dataLengthCounter & 0x00FF) | (value << 8); + break; + case 0x480B: _decompFlags = value & 0x03; + break; //Direct Data ROM Access (4810-481A) - case 0x4811: _readBase = (_readBase & 0xFFFF00) | value; break; - case 0x4812: _readBase = (_readBase & 0xFF00FF) | (value << 8); break; - case 0x4813: - _readBase = (_readBase & 0x00FFFF) | (value << 16); + case 0x4811: _readBase = (_readBase & 0xFFFF00) | value; + break; + case 0x4812: _readBase = (_readBase & 0xFF00FF) | (value << 8); + break; + case 0x4813: + _readBase = (_readBase & 0x00FFFF) | (value << 16); + FillReadBuffer(); + break; + + case 0x4814: + _readOffset = (_readOffset & 0xFF00) | value; + if ((_readMode & 0x60) == 0x20) + { + IncrementPosition(); + } + break; + + case 0x4815: + _readOffset = (_readOffset & 0x00FF) | (value << 8); + if (_readMode & 0x02) + { FillReadBuffer(); - break; + } + if ((_readMode & 0x60) == 0x40) + { + IncrementPosition(); + } + break; - case 0x4814: - _readOffset = (_readOffset & 0xFF00) | value; - if((_readMode & 0x60) == 0x20) { - IncrementPosition(); - } - break; + case 0x4816: _readStep = (_readStep & 0xFF00) | value; + break; + case 0x4817: _readStep = (_readStep & 0x00FF) | (value << 8); + break; - case 0x4815: - _readOffset = (_readOffset & 0x00FF) | (value << 8); - if(_readMode & 0x02) { - FillReadBuffer(); - } - if((_readMode & 0x60) == 0x40) { - IncrementPosition(); - } - break; - - case 0x4816: _readStep = (_readStep & 0xFF00) | value; break; - case 0x4817: _readStep = (_readStep & 0x00FF) | (value << 8); break; - - case 0x4818: - _readMode = value & 0x7F; - FillReadBuffer(); - break; + case 0x4818: + _readMode = value & 0x7F; + FillReadBuffer(); + break; //ALU (4820-482F) - case 0x4820: _dividend = (_dividend & 0xFFFFFF00) | value; break; - case 0x4821: _dividend = (_dividend & 0xFFFF00FF) | (value << 8); break; - case 0x4822: _dividend = (_dividend & 0xFF00FFFF) | (value << 16); break; - case 0x4823: _dividend = (_dividend & 0x00FFFFFF) | (value << 24); break; - case 0x4824: _multiplier = (_multiplier & 0xFF00) | value; break; - case 0x4825: - _multiplier = (_multiplier & 0x00FF) | (value << 8); - ProcessMultiplication(); - break; + case 0x4820: _dividend = (_dividend & 0xFFFFFF00) | value; + break; + case 0x4821: _dividend = (_dividend & 0xFFFF00FF) | (value << 8); + break; + case 0x4822: _dividend = (_dividend & 0xFF00FFFF) | (value << 16); + break; + case 0x4823: _dividend = (_dividend & 0x00FFFFFF) | (value << 24); + break; + case 0x4824: _multiplier = (_multiplier & 0xFF00) | value; + break; + case 0x4825: + _multiplier = (_multiplier & 0x00FF) | (value << 8); + ProcessMultiplication(); + break; - case 0x4826: _divisor = (_divisor & 0xFF00) | value; break; - case 0x4827: - _divisor = (_divisor & 0x00FF) | (value << 8); - ProcessDivision(); - break; + case 0x4826: _divisor = (_divisor & 0xFF00) | value; + break; + case 0x4827: + _divisor = (_divisor & 0x00FF) | (value << 8); + ProcessDivision(); + break; - case 0x482E: _aluFlags = value & 0x01; break; + case 0x482E: _aluFlags = value & 0x01; + break; //Memory mapping (4830-4834) - case 0x4830: _sramEnabled = value & 0x87; break; - case 0x4831: _dataRomBanks[0] = value & 0x07; UpdateMappings(); break; - case 0x4832: _dataRomBanks[1] = value & 0x07; UpdateMappings(); break; - case 0x4833: _dataRomBanks[2] = value & 0x07; UpdateMappings(); break; - case 0x4834: _dataRomSize = value & 0x07; break; + case 0x4830: _sramEnabled = value & 0x87; + break; + case 0x4831: _dataRomBanks[0] = value & 0x07; + UpdateMappings(); + break; + case 0x4832: _dataRomBanks[1] = value & 0x07; + UpdateMappings(); + break; + case 0x4833: _dataRomBanks[2] = value & 0x07; + UpdateMappings(); + break; + case 0x4834: _dataRomSize = value & 0x07; + break; //RTC (4840-4842) - case 0x4840: - case 0x4841: - case 0x4842: - if(_rtc) { - _rtc->Write(addr, value); - } - break; + case 0x4840: + case 0x4841: + case 0x4842: + if (_rtc) + { + _rtc->Write(addr, value); + } + break; - default: - if((addr & 0xFFFF) >= 0x4800) { - LogDebug("[Debug] Missing write handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); - } - _cpuRegisterHandler->Write(addr, value); - break; + default: + if ((addr & 0xFFFF) >= 0x4800) + { + LogDebug("[Debug] Missing write handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); + } + _cpuRegisterHandler->Write(addr, value); + break; } } @@ -267,17 +316,22 @@ void Spc7110::UpdateMappings() vector>& prgRomHandlers = _cart->GetPrgRomHandlers(); uint32_t dataRomSize = _realDataRomSize >> 12; - for(int i = 0; i < 3; i++) { - mappings->RegisterHandler(0xD0 + (i * 0x10), 0xDF + (i * 0x10), 0x0000, 0xFFFF, prgRomHandlers, 0, 0x100 + ((_dataRomBanks[i] * 0x100) % dataRomSize)); + for (int i = 0; i < 3; i++) + { + mappings->RegisterHandler(0xD0 + (i * 0x10), 0xDF + (i * 0x10), 0x0000, 0xFFFF, prgRomHandlers, 0, + 0x100 + ((_dataRomBanks[i] * 0x100) % dataRomSize)); } } void Spc7110::ProcessMultiplication() { - if(_aluFlags & 0x01) { + if (_aluFlags & 0x01) + { //Signed multiplication (16x16=32) _multDivResult = (int32_t)((int16_t)_dividend * (int16_t)_multiplier); - } else { + } + else + { //Unsigned multiplication (16x16=32) _multDivResult = (uint32_t)(_dividend * _multiplier); } @@ -288,24 +342,33 @@ void Spc7110::ProcessMultiplication() void Spc7110::ProcessDivision() { - if(_aluFlags & 0x01) { + if (_aluFlags & 0x01) + { //Signed division (32 / 16 = 32 + 16) int32_t dividend = (int32_t)_dividend; int16_t divisor = (int16_t)_divisor; - if(divisor != 0) { + if (divisor != 0) + { _multDivResult = (int32_t)(dividend / divisor); _remainder = ((int32_t)(dividend % divisor)) & 0xFFFF; - } else { + } + else + { _multDivResult = 0; _remainder = dividend & 0xFFFF; } - } else { + } + else + { //Unsigned division (32 / 16 = 32 + 16) - if(_divisor != 0) { + if (_divisor != 0) + { _multDivResult = _dividend / _divisor; _remainder = (uint16_t)(_dividend % _divisor); - } else { + } + else + { _multDivResult = 0; _remainder = _dividend & 0xffff; } @@ -318,7 +381,8 @@ uint8_t Spc7110::ReadDataRom(uint32_t addr) { uint32_t configSize = 0x100000 * (1 << (_dataRomSize & 0x03)); uint32_t dataRomSize = std::min(configSize, _realDataRomSize); - if(addr >= dataRomSize) { + if (addr >= dataRomSize) + { return 0x00; } @@ -328,7 +392,8 @@ uint8_t Spc7110::ReadDataRom(uint32_t addr) void Spc7110::FillReadBuffer() { int32_t offset = _readMode & 0x02 ? _readOffset : 0; - if(_readMode & 0x08) { + if (_readMode & 0x08) + { offset = (int16_t)offset; } _readBuffer = ReadDataRom(_readBase + offset); @@ -343,13 +408,17 @@ void Spc7110::IncrementPosition() void Spc7110::IncrementPosition4810() { int32_t step = _readMode & 0x01 ? _readStep : 1; - if(_readMode & 0x04) { + if (_readMode & 0x04) + { step = (int16_t)step; } - if(_readMode & 0x10) { + if (_readMode & 0x10) + { _readOffset += step; - } else { + } + else + { _readBase = (_readBase + step) & 0xFFFFFF; } @@ -365,7 +434,8 @@ void Spc7110::LoadEntryHeader() void Spc7110::BeginDecompression() { - if(_decompMode == 3) { + if (_decompMode == 3) + { return; } @@ -373,7 +443,8 @@ void Spc7110::BeginDecompression() _decomp->Decode(); uint32_t seek = _decompFlags & 0x02 ? _targetOffset : 0; - while(seek--) { + while (seek--) + { _decomp->Decode(); } @@ -383,32 +454,37 @@ void Spc7110::BeginDecompression() uint8_t Spc7110::ReadDecompressedByte() { - if((_decompStatus & 0x80) == 0) { + if ((_decompStatus & 0x80) == 0) + { return 0x00; } uint8_t bpp = _decomp->GetBpp(); - if(_decompOffset == 0) { - for(int i = 0; i < 8; i++) { + if (_decompOffset == 0) + { + for (int i = 0; i < 8; i++) + { uint32_t result = _decomp->GetResult(); - switch(bpp) { - case 1: - _decompBuffer[i] = result; - break; - case 2: - _decompBuffer[i * 2 + 0] = result >> 0; - _decompBuffer[i * 2 + 1] = result >> 8; - break; - case 4: - _decompBuffer[i * 2 + 0] = result >> 0; - _decompBuffer[i * 2 + 1] = result >> 8; - _decompBuffer[i * 2 + 16] = result >> 16; - _decompBuffer[i * 2 + 17] = result >> 24; - break; + switch (bpp) + { + case 1: + _decompBuffer[i] = result; + break; + case 2: + _decompBuffer[i * 2 + 0] = result >> 0; + _decompBuffer[i * 2 + 1] = result >> 8; + break; + case 4: + _decompBuffer[i * 2 + 0] = result >> 0; + _decompBuffer[i * 2 + 1] = result >> 8; + _decompBuffer[i * 2 + 16] = result >> 16; + _decompBuffer[i * 2 + 17] = result >> 24; + break; } uint32_t seek = (_decompFlags & 0x01) ? _skipBytes : 1; - while(seek--) { + while (seek--) + { _decomp->Decode(); } } @@ -431,7 +507,7 @@ void Spc7110::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo Spc7110::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void Spc7110::Reset() @@ -471,21 +547,24 @@ void Spc7110::Reset() UpdateMappings(); _decomp.reset(new Spc7110Decomp(this)); - if(_useRtc) { + if (_useRtc) + { _rtc.reset(new Rtc4513(_console)); } } void Spc7110::LoadBattery() { - if(_rtc) { + if (_rtc) + { _rtc->LoadBattery(); } } void Spc7110::SaveBattery() { - if(_rtc) { + if (_rtc) + { _rtc->SaveBattery(); } } diff --git a/Core/Spc7110.h b/Core/Spc7110.h index 027bf8f..9aac623 100644 --- a/Core/Spc7110.h +++ b/Core/Spc7110.h @@ -45,7 +45,7 @@ private: //Memory mappings uint8_t _sramEnabled = 0; - uint8_t _dataRomBanks[3] = { 0, 1, 2 }; + uint8_t _dataRomBanks[3] = {0, 1, 2}; uint8_t _dataRomSize = 0; //Data rom @@ -68,7 +68,7 @@ private: public: Spc7110(Console* console, bool useRtc); - + uint8_t ReadDataRom(uint32_t addr); void Serialize(Serializer& s) override; @@ -82,4 +82,4 @@ public: void LoadBattery() override; void SaveBattery() override; -}; \ No newline at end of file +}; diff --git a/Core/Spc7110Decomp.cpp b/Core/Spc7110Decomp.cpp index 3abaeb5..4063ab6 100644 --- a/Core/Spc7110Decomp.cpp +++ b/Core/Spc7110Decomp.cpp @@ -36,8 +36,10 @@ uint32_t Spc7110Decomp::Deinterleave(uint64_t data, uint32_t bits) //extract a nibble and move it to the low four bits uint64_t Spc7110Decomp::MoveToFront(uint64_t list, uint32_t nibble) { - for(uint64_t n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) { - if((list >> n & 15) != nibble) { + for (uint64_t n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) + { + if ((list >> n & 15) != nibble) + { continue; } return (list & mask) + (list << 4 & ~mask) + nibble; @@ -62,21 +64,24 @@ void Spc7110Decomp::Initialize(uint32_t mode, uint32_t origin) void Spc7110Decomp::Decode() { - for(uint32_t pixel = 0; pixel < 8; pixel++) { + for (uint32_t pixel = 0; pixel < 8; pixel++) + { uint64_t map = _colormap; uint32_t diff = 0; - if(_bpp > 1) { + if (_bpp > 1) + { uint32_t pa = (_bpp == 2 ? (_pixels >> 2) & 3 : (_pixels >> 0) & 15); uint32_t pb = (_bpp == 2 ? (_pixels >> 14) & 3 : (_pixels >> 28) & 15); uint32_t pc = (_bpp == 2 ? (_pixels >> 16) & 3 : (_pixels >> 32) & 15); - if(pa != pb || pb != pc) { + if (pa != pb || pb != pc) + { uint32_t match = pa ^ pb ^ pc; - diff = 4; //no match; all pixels differ - if((match ^ pc) == 0) diff = 3; //a == b; pixel c differs - if((match ^ pb) == 0) diff = 2; //c == a; pixel b differs - if((match ^ pa) == 0) diff = 1; //b == c; pixel a differs + diff = 4; //no match; all pixels differ + if ((match ^ pc) == 0) diff = 3; //a == b; pixel c differs + if ((match ^ pb) == 0) diff = 2; //c == a; pixel b differs + if ((match ^ pa) == 0) diff = 1; //b == c; pixel a differs } _colormap = MoveToFront(_colormap, pa); @@ -86,65 +91,85 @@ void Spc7110Decomp::Decode() map = MoveToFront(map, pa); } - for(uint32_t plane = 0; plane < _bpp; plane++) { + for (uint32_t plane = 0; plane < _bpp; plane++) + { uint32_t bit = _bpp > 1 ? 1 << plane : 1 << (pixel & 3); uint32_t history = (bit - 1) & _output; uint32_t set = 0; - if(_bpp == 1) { + if (_bpp == 1) + { set = pixel >= 4; - } else if(_bpp == 2) { + } + else if (_bpp == 2) + { set = diff; } - if(plane >= 2 && history <= 1) { + if (plane >= 2 && history <= 1) + { set = diff; } auto& ctx = _context[set][bit + history - 1]; auto& model = evolution[ctx.prediction]; uint8_t lps_offset = _range - model.probability; - bool symbol = _input >= (lps_offset << 8); //test only the MSB + bool symbol = _input >= (lps_offset << 8); //test only the MSB _output = _output << 1 | ((uint8_t)symbol ^ ctx.swap); - if(symbol == MPS) { //[0 ... range-p] - _range = lps_offset; //range = range-p - } else { //[range-p+1 ... range] - _range -= lps_offset; //range = p-1, with p < 0.75 - _input -= lps_offset << 8; //therefore, always rescale + if (symbol == MPS) + { + //[0 ... range-p] + _range = lps_offset; //range = range-p + } + else + { + //[range-p+1 ... range] + _range -= lps_offset; //range = p-1, with p < 0.75 + _input -= lps_offset << 8; //therefore, always rescale } - while(_range <= Max / 2) { //scale back into [0.75 ... 1.5] + while (_range <= Max / 2) + { + //scale back into [0.75 ... 1.5] ctx.prediction = model.next[symbol]; _range <<= 1; _input <<= 1; - if(--_bits == 0) { + if (--_bits == 0) + { _bits = 8; _input += ReadByte(); } } - if(symbol == LPS && model.probability > Half) { + if (symbol == LPS && model.probability > Half) + { ctx.swap ^= 1; } } uint32_t index = _output & ((1 << _bpp) - 1); - if(_bpp == 1) { + if (_bpp == 1) + { index ^= _pixels >> 15 & 1; } _pixels = _pixels << _bpp | (map >> 4 * index & 15); } - if(_bpp == 1) { + if (_bpp == 1) + { _result = (uint32_t)_pixels; - } else if(_bpp == 2) { + } + else if (_bpp == 2) + { _result = Deinterleave(_pixels, 16); - } else if(_bpp == 4) { + } + else if (_bpp == 4) + { _result = Deinterleave(Deinterleave(_pixels, 32), 32); } } @@ -162,35 +187,37 @@ uint8_t Spc7110Decomp::GetBpp() void Spc7110Decomp::Serialize(Serializer& s) { s.Stream(_bpp, _offset, _bits, _range, _input, _output, _pixels, _colormap, _result); - for(int i = 0; i < 5; i++) { - for(int j = 0; j < 15; j++) { + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < 15; j++) + { s.Stream(_context[i][j].swap, _context[i][j].prediction); } } } Spc7110Decomp::ModelState Spc7110Decomp::evolution[53] = { - {0x5a, { 1, 1}}, {0x25, { 2, 6}}, {0x11, { 3, 8}}, - {0x08, { 4,10}}, {0x03, { 5,12}}, {0x01, { 5,15}}, + {0x5a, {1, 1}}, {0x25, {2, 6}}, {0x11, {3, 8}}, + {0x08, {4, 10}}, {0x03, {5, 12}}, {0x01, {5, 15}}, - {0x5a, { 7, 7}}, {0x3f, { 8,19}}, {0x2c, { 9,21}}, - {0x20, {10,22}}, {0x17, {11,23}}, {0x11, {12,25}}, - {0x0c, {13,26}}, {0x09, {14,28}}, {0x07, {15,29}}, - {0x05, {16,31}}, {0x04, {17,32}}, {0x03, {18,34}}, - {0x02, { 5,35}}, + {0x5a, {7, 7}}, {0x3f, {8, 19}}, {0x2c, {9, 21}}, + {0x20, {10, 22}}, {0x17, {11, 23}}, {0x11, {12, 25}}, + {0x0c, {13, 26}}, {0x09, {14, 28}}, {0x07, {15, 29}}, + {0x05, {16, 31}}, {0x04, {17, 32}}, {0x03, {18, 34}}, + {0x02, {5, 35}}, - {0x5a, {20,20}}, {0x48, {21,39}}, {0x3a, {22,40}}, - {0x2e, {23,42}}, {0x26, {24,44}}, {0x1f, {25,45}}, - {0x19, {26,46}}, {0x15, {27,25}}, {0x11, {28,26}}, - {0x0e, {29,26}}, {0x0b, {30,27}}, {0x09, {31,28}}, - {0x08, {32,29}}, {0x07, {33,30}}, {0x05, {34,31}}, - {0x04, {35,33}}, {0x04, {36,33}}, {0x03, {37,34}}, - {0x02, {38,35}}, {0x02, { 5,36}}, + {0x5a, {20, 20}}, {0x48, {21, 39}}, {0x3a, {22, 40}}, + {0x2e, {23, 42}}, {0x26, {24, 44}}, {0x1f, {25, 45}}, + {0x19, {26, 46}}, {0x15, {27, 25}}, {0x11, {28, 26}}, + {0x0e, {29, 26}}, {0x0b, {30, 27}}, {0x09, {31, 28}}, + {0x08, {32, 29}}, {0x07, {33, 30}}, {0x05, {34, 31}}, + {0x04, {35, 33}}, {0x04, {36, 33}}, {0x03, {37, 34}}, + {0x02, {38, 35}}, {0x02, {5, 36}}, - {0x58, {40,39}}, {0x4d, {41,47}}, {0x43, {42,48}}, - {0x3b, {43,49}}, {0x34, {44,50}}, {0x2e, {45,51}}, - {0x29, {46,44}}, {0x25, {24,45}}, + {0x58, {40, 39}}, {0x4d, {41, 47}}, {0x43, {42, 48}}, + {0x3b, {43, 49}}, {0x34, {44, 50}}, {0x2e, {45, 51}}, + {0x29, {46, 44}}, {0x25, {24, 45}}, - {0x56, {48,47}}, {0x4f, {49,47}}, {0x47, {50,48}}, - {0x41, {51,49}}, {0x3c, {52,50}}, {0x37, {43,51}}, -}; \ No newline at end of file + {0x56, {48, 47}}, {0x4f, {49, 47}}, {0x47, {50, 48}}, + {0x41, {51, 49}}, {0x3c, {52, 50}}, {0x37, {43, 51}}, +}; diff --git a/Core/Spc7110Decomp.h b/Core/Spc7110Decomp.h index 50a0629..04e31a9 100644 --- a/Core/Spc7110Decomp.h +++ b/Core/Spc7110Decomp.h @@ -12,33 +12,36 @@ class Spc7110Decomp : public ISerializable { private: enum : uint32_t { MPS = 0, LPS = 1 }; + enum : uint32_t { One = 0xAA, Half = 0x55, Max = 0xFF }; struct ModelState { - uint8_t probability; //of the more probable symbol (MPS) - uint8_t next[2]; //next state after output {MPS, LPS} + uint8_t probability; //of the more probable symbol (MPS) + uint8_t next[2]; //next state after output {MPS, LPS} }; + static ModelState evolution[53]; struct Context { - uint8_t prediction; //current model state - uint8_t swap; //if 1, exchange the role of MPS and LPS - }; - Context _context[5][15]; //not all 75 contexts exists; this simplifies the code + uint8_t prediction; //current model state + uint8_t swap; //if 1, exchange the role of MPS and LPS + }; + + Context _context[5][15]; //not all 75 contexts exists; this simplifies the code Spc7110* _spc; - uint32_t _bpp; //bits per pixel (1bpp = 1; 2bpp = 2; 4bpp = 4) - uint32_t _offset; //SPC7110 data ROM read offset - uint32_t _bits; //bits remaining in input - uint16_t _range; //arithmetic range: technically 8-bits, but Max+1 = 256 - uint16_t _input; //input data from SPC7110 data ROM + uint32_t _bpp; //bits per pixel (1bpp = 1; 2bpp = 2; 4bpp = 4) + uint32_t _offset; //SPC7110 data ROM read offset + uint32_t _bits; //bits remaining in input + uint16_t _range; //arithmetic range: technically 8-bits, but Max+1 = 256 + uint16_t _input; //input data from SPC7110 data ROM uint8_t _output; uint64_t _pixels; - uint64_t _colormap; //most recently used list - uint32_t _result; //decompressed word after calling decode() + uint64_t _colormap; //most recently used list + uint32_t _result; //decompressed word after calling decode() private: uint8_t ReadByte(); @@ -55,4 +58,4 @@ public: uint8_t GetBpp(); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SpcDebugger.cpp b/Core/SpcDebugger.cpp index 65790d4..b26f166 100644 --- a/Core/SpcDebugger.cpp +++ b/Core/SpcDebugger.cpp @@ -36,22 +36,26 @@ void SpcDebugger::Reset() void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { - if(type == MemoryOperationType::DummyRead) { + if (type == MemoryOperationType::DummyRead) + { //Ignore all dummy reads for now return; } AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; BreakSource breakSource = BreakSource::Unspecified; - if(type == MemoryOperationType::ExecOpCode) { + if (type == MemoryOperationType::ExecOpCode) + { SpcState spcState = _spc->GetState(); - if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { + if (_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { _disassembler->BuildCache(addressInfo, 0, CpuType::Spc); - if(_traceLogger->IsCpuLogged(CpuType::Spc)) { + if (_traceLogger->IsCpuLogged(CpuType::Spc)) + { _debugger->GetState(_debugState, true); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc); @@ -59,19 +63,24 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType } } - if(_prevOpCode == 0x3F || _prevOpCode == 0x0F) { + if (_prevOpCode == 0x3F || _prevOpCode == 0x0F) + { //JSR, BRK uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); uint16_t returnPc = _prevProgramCounter + opSize; AddressInfo src = _spc->GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = _spc->GetAbsoluteAddress(returnPc); - _callstackManager->Push(src, _prevProgramCounter, addressInfo, spcState.PC, ret, returnPc, StackFrameFlags::None); - } else if(_prevOpCode == 0x6F || _prevOpCode == 0x7F) { + _callstackManager->Push(src, _prevProgramCounter, addressInfo, spcState.PC, ret, returnPc, + StackFrameFlags::None); + } + else if (_prevOpCode == 0x6F || _prevOpCode == 0x7F) + { //RTS, RTI _callstackManager->Pop(addressInfo, spcState.PC); } - if(_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) { + if (_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) + { //RTS/RTI found, if we're on the expected return address, break immediately (for step over/step out) _step->StepCount = 0; } @@ -79,34 +88,44 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType _prevOpCode = value; _prevProgramCounter = spcState.PC; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } - if(_settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { //Break on BRK/STP - if(value == 0x0F && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { + if (value == 0x0F && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) + { breakSource = BreakSource::BreakOnBrk; _step->StepCount = 0; - } else if(value == 0xFF && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) { + } + else if (value == 0xFF && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) + { breakSource = BreakSource::BreakOnStp; _step->StepCount = 0; } } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else if(type == MemoryOperationType::ExecOperand) { + } + else if (type == MemoryOperationType::ExecOperand) + { _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else { + } + else + { _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); } - _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource); + _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, + breakSource); } void SpcDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo { addr, SnesMemoryType::SpcRam }; //Writes never affect the SPC ROM - MemoryOperationInfo operation { addr, value, type }; + AddressInfo addressInfo{addr, SnesMemoryType::SpcRam}; //Writes never affect the SPC ROM + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); _disassembler->InvalidateCache(addressInfo, CpuType::Spc); @@ -123,22 +142,28 @@ void SpcDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; - case StepType::StepOver: - if(_prevOpCode == 0x3F || _prevOpCode == 0x0F) { - //JSR, BRK - step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); - } else { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - break; - - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; + case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); + break; + case StepType::StepOver: + if (_prevOpCode == 0x3F || _prevOpCode == 0x0F) + { + //JSR, BRK + step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); + } + else + { + //For any other instruction, step over is the same as step into + step.StepCount = 1; + } + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -152,4 +177,4 @@ shared_ptr SpcDebugger::GetCallstackManager() BreakpointManager* SpcDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/SpcDebugger.h b/Core/SpcDebugger.h index 908f3c5..7c412df 100644 --- a/Core/SpcDebugger.h +++ b/Core/SpcDebugger.h @@ -29,7 +29,7 @@ class SpcDebugger final : public IDebugger uint8_t _prevOpCode = 0xFF; uint32_t _prevProgramCounter = 0; - + DebugState _debugState; public: @@ -43,4 +43,4 @@ public: void Step(int32_t stepCount, StepType type); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/SpcDisUtils.cpp b/Core/SpcDisUtils.cpp index 791baf9..2839532 100644 --- a/Core/SpcDisUtils.cpp +++ b/Core/SpcDisUtils.cpp @@ -9,41 +9,73 @@ #include "../Utilities/HexUtilities.h" constexpr const char* _altOpTemplate[256] = { - "NOP", "TCALL 0", "SET1 d.0", "BBS d.0,q", "OR A,d", "OR A,!a", "OR A,(X)", "OR A,[d+X]", "OR A,#i", "OR t,s", "OR1 C,m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK", - "BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0,q", "OR A,d+X", "OR A,!a+X", "OR A,!a+Y", "OR A,[d]+Y", "OR e,#i", "OR (X),(Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X,!a", "JMP [!a+X]", - "CLRP", "TCALL 2", "SET1 d.1", "BBS d.1,q", "AND A,d", "AND A,!a", "AND A,(X)", "AND A,[d+X]", "AND A,#i", "AND t,s", "OR1 C,/m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d,q", "BRA r", - "BMI r", "TCALL 3", "CLR1 d.1", "BBC d.1,q", "AND A,d+X", "AND A,!a+X", "AND A,!a+Y", "AND A,[d]+Y", "AND e,#i", "AND (X),(Y)", "INCW d", "ROL d+X", "ROL A", "INC X", "CMP X,d", "CALL !a", - "SETP", "TCALL 4", "SET1 d.2", "BBS d.2,q", "EOR A,d", "EOR A,!a", "EOR A,(X)", "EOR A,[d+X]", "EOR A,#i", "EOR t,s", "AND1 C,m.b", "LSR d", "LSR !a", "PUSH X", "TCLR1 !a", "PCALL u", - "BVC r", "TCALL 5", "CLR1 d.2", "BBC d.2,q", "EOR A,d+X", "EOR A,!a+X", "EOR A,!a+Y", "EOR A,[d]+Y", "EOR e,#i", "EOR (X),(Y)", "CMPW YA,d", "LSR d+X", "LSR A", "MOV X,A", "CMP Y,!a", "JMP !a", - "CLRC", "TCALL 6", "SET1 d.3", "BBS d.3,q", "CMP A,d", "CMP A,!a", "CMP A,(X)", "CMP A,[d+X]", "CMP A,#i", "CMP t,s", "AND1 C,/m.b", "ROR d", "ROR !a", "PUSH Y", "DBNZ d,q", "RET", - "BVS r", "TCALL 7", "CLR1 d.3", "BBC d.3,q", "CMP A,d+X", "CMP A,!a+X", "CMP A,!a+Y", "CMP A,[d]+Y", "CMP e,#i", "CMP (X),(Y)", "ADDW YA,d", "ROR d+X", "ROR A", "MOV A,X", "CMP Y,d", "RET1", - "SETC", "TCALL 8", "SET1 d.4", "BBS d.4,q", "ADC A,d", "ADC A,!a", "ADC A,(X)", "ADC A,[d+X]", "ADC A,#i", "ADC t,s", "EOR1 C,m.b", "DEC d", "DEC !a", "MOV Y,#i", "POP PSW", "MOV e,#i", - "BCC r", "TCALL 9", "CLR1 d.4", "BBC d.4,q", "ADC A,d+X", "ADC A,!a+X", "ADC A,!a+Y", "ADC A,[d]+Y", "ADC e,#i", "ADC (X),(Y)", "SUBW YA,d", "DEC d+X", "DEC A", "MOV X,SP", "DIV YA,X", "XCN A", - "EI", "TCALL 10", "SET1 d.5", "BBS d.5,q", "SBC A,d", "SBC A,!a", "SBC A,(X)", "SBC A,[d+X]", "SBC A,#i", "SBC t,s", "MOV1 C,m.b", "INC d", "INC !a", "CMP Y,#i", "POP A", "MOV (X)+,A", - "BCS r", "TCALL 11", "CLR1 d.5", "BBC d.5,q", "SBC A,d+X", "SBC A,!a+X", "SBC A,!a+Y", "SBC A,[d]+Y", "SBC e,#i", "SBC (X),(Y)", "MOVW YA,d", "INC d+X", "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+", - "DI", "TCALL 12", "SET1 d.6", "BBS d.6,q", "MOV d,A", "MOV !a,A", "MOV (X),A", "MOV [d+X],A", "CMP X,#i", "MOV !a,X", "MOV1 m.b,C", "MOV d,Y", "MOV !a,Y", "MOV X,#i", "POP X", "MUL YA", - "BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6,q", "MOV d+X,A", "MOV !a+X,A", "MOV !a+Y,A", "MOV [d]+Y,A", "MOV e,X", "MOV d+Y,X", "MOVW d,YA", "MOV d+X,Y", "DEC Y", "MOV A,Y", "CBNE d+X,q", "DAA A", - "CLRV", "TCALL 14", "SET1 d.7", "BBS d.7,q", "MOV A,d", "MOV A,!a", "MOV A,(X)", "MOV A,[d+X]", "MOV A,#i", "MOV X,!a", "NOT1 m.b", "MOV Y,d", "MOV Y,!a", "NOTC", "POP Y", "SLEEP", - "BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7,q", "MOV A,d+X", "MOV A,!a+X", "MOV A,!a+Y", "MOV A,[d]+Y", "MOV X,d", "MOV X,d+Y", "MOV t,s", "MOV Y,d+X", "INC Y", "MOV Y,A", "DBNZ Y,q", "STOP" + "NOP", "TCALL 0", "SET1 d.0", "BBS d.0,q", "OR A,d", "OR A,!a", "OR A,(X)", "OR A,[d+X]", "OR A,#i", "OR t,s", + "OR1 C,m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK", + "BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0,q", "OR A,d+X", "OR A,!a+X", "OR A,!a+Y", "OR A,[d]+Y", "OR e,#i", + "OR (X),(Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X,!a", "JMP [!a+X]", + "CLRP", "TCALL 2", "SET1 d.1", "BBS d.1,q", "AND A,d", "AND A,!a", "AND A,(X)", "AND A,[d+X]", "AND A,#i", "AND t,s", + "OR1 C,/m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d,q", "BRA r", + "BMI r", "TCALL 3", "CLR1 d.1", "BBC d.1,q", "AND A,d+X", "AND A,!a+X", "AND A,!a+Y", "AND A,[d]+Y", "AND e,#i", + "AND (X),(Y)", "INCW d", "ROL d+X", "ROL A", "INC X", "CMP X,d", "CALL !a", + "SETP", "TCALL 4", "SET1 d.2", "BBS d.2,q", "EOR A,d", "EOR A,!a", "EOR A,(X)", "EOR A,[d+X]", "EOR A,#i", "EOR t,s", + "AND1 C,m.b", "LSR d", "LSR !a", "PUSH X", "TCLR1 !a", "PCALL u", + "BVC r", "TCALL 5", "CLR1 d.2", "BBC d.2,q", "EOR A,d+X", "EOR A,!a+X", "EOR A,!a+Y", "EOR A,[d]+Y", "EOR e,#i", + "EOR (X),(Y)", "CMPW YA,d", "LSR d+X", "LSR A", "MOV X,A", "CMP Y,!a", "JMP !a", + "CLRC", "TCALL 6", "SET1 d.3", "BBS d.3,q", "CMP A,d", "CMP A,!a", "CMP A,(X)", "CMP A,[d+X]", "CMP A,#i", "CMP t,s", + "AND1 C,/m.b", "ROR d", "ROR !a", "PUSH Y", "DBNZ d,q", "RET", + "BVS r", "TCALL 7", "CLR1 d.3", "BBC d.3,q", "CMP A,d+X", "CMP A,!a+X", "CMP A,!a+Y", "CMP A,[d]+Y", "CMP e,#i", + "CMP (X),(Y)", "ADDW YA,d", "ROR d+X", "ROR A", "MOV A,X", "CMP Y,d", "RET1", + "SETC", "TCALL 8", "SET1 d.4", "BBS d.4,q", "ADC A,d", "ADC A,!a", "ADC A,(X)", "ADC A,[d+X]", "ADC A,#i", "ADC t,s", + "EOR1 C,m.b", "DEC d", "DEC !a", "MOV Y,#i", "POP PSW", "MOV e,#i", + "BCC r", "TCALL 9", "CLR1 d.4", "BBC d.4,q", "ADC A,d+X", "ADC A,!a+X", "ADC A,!a+Y", "ADC A,[d]+Y", "ADC e,#i", + "ADC (X),(Y)", "SUBW YA,d", "DEC d+X", "DEC A", "MOV X,SP", "DIV YA,X", "XCN A", + "EI", "TCALL 10", "SET1 d.5", "BBS d.5,q", "SBC A,d", "SBC A,!a", "SBC A,(X)", "SBC A,[d+X]", "SBC A,#i", "SBC t,s", + "MOV1 C,m.b", "INC d", "INC !a", "CMP Y,#i", "POP A", "MOV (X)+,A", + "BCS r", "TCALL 11", "CLR1 d.5", "BBC d.5,q", "SBC A,d+X", "SBC A,!a+X", "SBC A,!a+Y", "SBC A,[d]+Y", "SBC e,#i", + "SBC (X),(Y)", "MOVW YA,d", "INC d+X", "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+", + "DI", "TCALL 12", "SET1 d.6", "BBS d.6,q", "MOV d,A", "MOV !a,A", "MOV (X),A", "MOV [d+X],A", "CMP X,#i", "MOV !a,X", + "MOV1 m.b,C", "MOV d,Y", "MOV !a,Y", "MOV X,#i", "POP X", "MUL YA", + "BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6,q", "MOV d+X,A", "MOV !a+X,A", "MOV !a+Y,A", "MOV [d]+Y,A", "MOV e,X", + "MOV d+Y,X", "MOVW d,YA", "MOV d+X,Y", "DEC Y", "MOV A,Y", "CBNE d+X,q", "DAA A", + "CLRV", "TCALL 14", "SET1 d.7", "BBS d.7,q", "MOV A,d", "MOV A,!a", "MOV A,(X)", "MOV A,[d+X]", "MOV A,#i", + "MOV X,!a", "NOT1 m.b", "MOV Y,d", "MOV Y,!a", "NOTC", "POP Y", "SLEEP", + "BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7,q", "MOV A,d+X", "MOV A,!a+X", "MOV A,!a+Y", "MOV A,[d]+Y", "MOV X,d", + "MOV X,d+Y", "MOV t,s", "MOV Y,d+X", "INC Y", "MOV Y,A", "DBNZ Y,q", "STOP" }; constexpr const char* _opTemplate[256] = { - "NOP", "JST0", "SET1 d.0", "BBS d.0,q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t,s", "ORC m.b", "ASL d", "ASL a", "PHP", "SET1 a", "BRK", - "BPL r", "JST1", "CLR1 d.0", "BBC d.0,q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e,#i", "OR (X),(Y)", "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]", - "CLP", "JST2", "SET1 d.1", "BBS d.1,q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t,s", "ORC /m.b", "ROL d", "ROL a", "PHA", "CBNE d,q", "BRA r", - "BMI r", "JST3", "CLR1 d.1", "BBC d.1,q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e,#i", "AND (X),(Y)", "INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a", - "SEP", "JST4", "SET1 d.2", "BBS d.2,q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t,s", "ANDC m.b", "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u", - "BVC r", "JST5", "CLR1 d.2", "BBC d.2,q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e,#i", "EOR (X),(Y)", "CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a", - "CLC", "JST6", "SET1 d.3", "BBS d.3,q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t,s", "ANDC /m.b", "ROR d", "ROR a", "PHY", "DBNZ d,q", "RTS", - "BVS r", "JST7", "CLR1 d.3", "BBC d.3,q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e,#i", "CMP (X),(Y)", "ADW d", "ROR d,X", "ROR A", "TXA", "CPY d", "RTI", - "SEC", "JST8", "SET1 d.4", "BBS d.4,q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t,s", "EORC m.b", "DEC d", "DEC a", "LDY #i","PLP", "MOV e,#i", - "BCC r", "JST9", "CLR1 d.4", "BBC d.4,q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e,#i", "ADC (X),(Y)", "SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA,X", "XCN A", - "CLI", "JSTA", "SET1 d.5", "BBS d.5,q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t,s", "LDC m.b", "INC d", "INC a", "CMY #i","PLA", "STA (X)+,A", - "BCS r", "JSTB", "CLR1 d.5", "BBC d.5,q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e,#i", "SBC (X),(Y)", "LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+", - "SEI", "JSTC", "SET1 d.6", "BBS d.6,q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", "STY d", "STY a", "LDX #i","PLX", "MUL YA", - "BNE r", "JSTD", "CLR1 d.6", "BBC d.6,q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX d", "STX d,Y", "STW d", "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A", - "CLV", "JSTE", "SET1 d.7", "BBS d.7,q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", "LDY d", "LDY a", "NOTC", "PLY", "WAI", - "BEQ r", "JSTF", "CLR1 d.7", "BBC d.7,q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", "MOV t,s", "LDY d,X", "INC Y", "TAY", "DBNZ Y,r", "STP" + "NOP", "JST0", "SET1 d.0", "BBS d.0,q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t,s", "ORC m.b", + "ASL d", "ASL a", "PHP", "SET1 a", "BRK", + "BPL r", "JST1", "CLR1 d.0", "BBC d.0,q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e,#i", "OR (X),(Y)", + "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]", + "CLP", "JST2", "SET1 d.1", "BBS d.1,q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t,s", "ORC /m.b", + "ROL d", "ROL a", "PHA", "CBNE d,q", "BRA r", + "BMI r", "JST3", "CLR1 d.1", "BBC d.1,q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e,#i", "AND (X),(Y)", + "INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a", + "SEP", "JST4", "SET1 d.2", "BBS d.2,q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t,s", "ANDC m.b", + "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u", + "BVC r", "JST5", "CLR1 d.2", "BBC d.2,q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e,#i", "EOR (X),(Y)", + "CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a", + "CLC", "JST6", "SET1 d.3", "BBS d.3,q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t,s", "ANDC /m.b", + "ROR d", "ROR a", "PHY", "DBNZ d,q", "RTS", + "BVS r", "JST7", "CLR1 d.3", "BBC d.3,q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e,#i", "CMP (X),(Y)", + "ADW d", "ROR d,X", "ROR A", "TXA", "CPY d", "RTI", + "SEC", "JST8", "SET1 d.4", "BBS d.4,q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t,s", "EORC m.b", + "DEC d", "DEC a", "LDY #i", "PLP", "MOV e,#i", + "BCC r", "JST9", "CLR1 d.4", "BBC d.4,q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e,#i", "ADC (X),(Y)", + "SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA,X", "XCN A", + "CLI", "JSTA", "SET1 d.5", "BBS d.5,q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t,s", "LDC m.b", + "INC d", "INC a", "CMY #i", "PLA", "STA (X)+,A", + "BCS r", "JSTB", "CLR1 d.5", "BBC d.5,q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e,#i", "SBC (X),(Y)", + "LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+", + "SEI", "JSTC", "SET1 d.6", "BBS d.6,q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", + "STY d", "STY a", "LDX #i", "PLX", "MUL YA", + "BNE r", "JSTD", "CLR1 d.6", "BBC d.6,q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX d", "STX d,Y", "STW d", + "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A", + "CLV", "JSTE", "SET1 d.7", "BBS d.7,q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", + "LDY d", "LDY a", "NOTC", "PLY", "WAI", + "BEQ r", "JSTF", "CLR1 d.7", "BBC d.7,q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", + "MOV t,s", "LDY d,X", "INC Y", "TAY", "DBNZ Y,r", "STP" }; constexpr const uint8_t _opSize[256] = { @@ -67,60 +99,80 @@ constexpr const uint8_t _opSize[256] = { constexpr bool _needAddress[256] = { false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false + false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false }; -void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings) +void SpcDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - AddressInfo addrInfo { 0, SnesMemoryType::SpcMemory }; - auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) { + AddressInfo addrInfo{0, SnesMemoryType::SpcMemory}; + auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) + { addrInfo.Address = addr; string label = labelManager ? labelManager->GetLabel(addrInfo) : ""; - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex(addr)); - } else { + } + else + { str.Write(label, true); } }; uint8_t* byteCode = info.GetByteCode(); - const char* op = settings->CheckDebuggerFlag(DebuggerFlags::UseAltSpcOpNames) ? _altOpTemplate[byteCode[0]] : _opTemplate[byteCode[0]]; + const char* op = settings->CheckDebuggerFlag(DebuggerFlags::UseAltSpcOpNames) + ? _altOpTemplate[byteCode[0]] + : _opTemplate[byteCode[0]]; int i = 0; - while(op[i]) { - switch(op[i]) { - case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break; - case 'q': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); break; //relative 2nd byte + while (op[i]) + { + switch (op[i]) + { + case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); + break; + case 'q': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); + break; //relative 2nd byte - case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); break; - - case 'd': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; - case 'e': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break; //direct 2nd byte + case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); + break; - case 's': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; - case 't': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break; + case 'd': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; + case 'e': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); + break; //direct 2nd byte - case 'i': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; + case 's': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; + case 't': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); + break; - case 'm': getOperand((uint16_t)((byteCode[1] | (byteCode[2] << 8)) & 0x1FFF)); break; - case 'b': str.WriteAll((char)('0' + (byteCode[2] >> 5))); break; + case 'i': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; - default: str.Write(op[i]); break; + case 'm': getOperand((uint16_t)((byteCode[1] | (byteCode[2] << 8)) & 0x1FFF)); + break; + case 'b': str.WriteAll((char)('0' + (byteCode[2] >> 5))); + break; + + default: str.Write(op[i]); + break; } i++; } @@ -128,18 +180,22 @@ void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me out += str.ToString(); } -int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console, SpcState &state) +int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, SpcState& state) { - if(_needAddress[info.GetOpCode()]) { + if (_needAddress[info.GetOpCode()]) + { Spc* spc = console->GetSpc().get(); DummySpc dummySpc(spc->GetSpcRam(), state); dummySpc.Step(); uint32_t addr; uint8_t value; uint32_t writeCount = dummySpc.GetWriteCount(); - if(writeCount > 0) { + if (writeCount > 0) + { dummySpc.GetWriteInfo(writeCount - 1, addr, value); - } else { + } + else + { uint32_t readCount = dummySpc.GetReadCount(); dummySpc.GetReadInfo(readCount - 1, addr, value); } diff --git a/Core/SpcDisUtils.h b/Core/SpcDisUtils.h index f52c736..dfcf81a 100644 --- a/Core/SpcDisUtils.h +++ b/Core/SpcDisUtils.h @@ -10,7 +10,8 @@ struct SpcState; class SpcDisUtils { public: - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); - static int32_t GetEffectiveAddress(DisassemblyInfo &info, Console *console, SpcState &state); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); + static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, SpcState& state); static uint8_t GetOpSize(uint8_t opCode); }; diff --git a/Core/SpcFileData.h b/Core/SpcFileData.h index a4bdb47..f2ab87b 100644 --- a/Core/SpcFileData.h +++ b/Core/SpcFileData.h @@ -66,4 +66,4 @@ public: TimerOutput[1] = spcData[0x100 + 0xFE]; TimerOutput[2] = spcData[0x100 + 0xFF]; } -}; \ No newline at end of file +}; diff --git a/Core/SpcHud.cpp b/Core/SpcHud.cpp index ddec3d1..ca5f398 100644 --- a/Core/SpcHud.cpp +++ b/Core/SpcHud.cpp @@ -5,7 +5,7 @@ #include "DebugHud.h" #include "SpcFileData.h" -SpcHud::SpcHud(Console * console, SpcFileData* spcData) +SpcHud::SpcHud(Console* console, SpcFileData* spcData) { _mixer = console->GetSoundMixer().get(); _hud = console->GetDebugHud().get(); @@ -29,8 +29,11 @@ void SpcHud::Draw(uint32_t frame) _volumesL[_volPosition] = left / 128; _volumesR[_volPosition] = right / 128; _volPosition = (_volPosition + 1) & 0x7F; - for(int i = 1; i < 128; i++) { - _hud->DrawLine((i - 1)*2, 160 + _volumesL[(_volPosition + i - 1) & 0x7F], i*2, 160 + _volumesL[(_volPosition + i) & 0x7F], 0x30FFAAAA, 1, frame); - _hud->DrawLine((i - 1)*2, 160 + _volumesR[(_volPosition + i - 1) & 0x7F], i*2, 160 + _volumesR[(_volPosition + i) & 0x7F], 0x30AAAAFF, 1, frame); + for (int i = 1; i < 128; i++) + { + _hud->DrawLine((i - 1) * 2, 160 + _volumesL[(_volPosition + i - 1) & 0x7F], i * 2, + 160 + _volumesL[(_volPosition + i) & 0x7F], 0x30FFAAAA, 1, frame); + _hud->DrawLine((i - 1) * 2, 160 + _volumesR[(_volPosition + i - 1) & 0x7F], i * 2, + 160 + _volumesR[(_volPosition + i) & 0x7F], 0x30AAAAFF, 1, frame); } } diff --git a/Core/SpcHud.h b/Core/SpcHud.h index 6f3239b..e96881d 100644 --- a/Core/SpcHud.h +++ b/Core/SpcHud.h @@ -22,4 +22,4 @@ public: SpcHud(Console* console, SpcFileData* spcData); void Draw(uint32_t frame); -}; \ No newline at end of file +}; diff --git a/Core/SpcTimer.h b/Core/SpcTimer.h index bfa9176..bf8b3f4 100644 --- a/Core/SpcTimer.h +++ b/Core/SpcTimer.h @@ -2,7 +2,7 @@ #include "stdafx.h" #include "../Utilities/Serializer.h" -template +template class SpcTimer { private: @@ -18,19 +18,22 @@ private: void ClockTimer() { uint8_t currentState = _stage1; - if(!_timersEnabled) { + if (!_timersEnabled) + { //All timers are disabled currentState = 0; } uint8_t prevState = _prevStage1; _prevStage1 = currentState; - if(!_enabled || !prevState || currentState) { + if (!_enabled || !prevState || currentState) + { //Only clock on 1->0 transitions, when the timer is enabled return; } - if(++_stage2 == _target) { + if (++_stage2 == _target) + { _stage2 = 0; _output++; } @@ -44,7 +47,8 @@ public: void SetEnabled(bool enabled) { - if(!_enabled && enabled) { + if (!_enabled && enabled) + { _stage2 = 0; _output = 0; } @@ -60,7 +64,8 @@ public: void Run(uint8_t step) { _stage0 += step; - if(_stage0 >= rate) { + if (_stage0 >= rate) + { _stage1 ^= 0x01; _stage0 -= rate; @@ -91,8 +96,8 @@ public: _output = value; } - void Serialize(Serializer &s) + void Serialize(Serializer& s) { s.Stream(_stage0, _stage1, _stage2, _output, _target, _enabled, _timersEnabled, _prevStage1); } -}; \ No newline at end of file +}; diff --git a/Core/SpcTypes.h b/Core/SpcTypes.h index 5213f03..1265867 100644 --- a/Core/SpcTypes.h +++ b/Core/SpcTypes.h @@ -36,21 +36,26 @@ struct DspState uint8_t Regs[128]; }; -namespace SpcFlags { +namespace SpcFlags +{ enum SpcFlags : uint8_t { Carry = 0x01, Zero = 0x02, - IrqEnable = 0x04, //unused + IrqEnable = 0x04, + //unused HalfCarry = 0x08, - Break = 0x10, /* Set by the BRK instruction */ - DirectPage = 0x20, /* Selects page 0 or 1 for direct mode addressing */ + Break = 0x10, + /* Set by the BRK instruction */ + DirectPage = 0x20, + /* Selects page 0 or 1 for direct mode addressing */ Overflow = 0x40, Negative = 0x80 }; } -namespace SpcControlFlags { +namespace SpcControlFlags +{ enum SpcControlFlags : uint8_t { Timer0 = 0x01, @@ -64,7 +69,8 @@ namespace SpcControlFlags { }; } -namespace SpcTestFlags { +namespace SpcTestFlags +{ enum SpcTestFlags : uint8_t { TimersDisabled = 0x01, @@ -83,4 +89,4 @@ enum class SpcOpStep : uint8_t Addressing = 1, AfterAddressing = 2, Operation = 3 -}; \ No newline at end of file +}; diff --git a/Core/SuperGameboy.cpp b/Core/SuperGameboy.cpp index 15c1533..b72722f 100644 --- a/Core/SuperGameboy.cpp +++ b/Core/SuperGameboy.cpp @@ -20,15 +20,16 @@ SuperGameboy::SuperGameboy(Console* console) : BaseCoprocessor(SnesMemoryType::R _memoryManager = console->GetMemoryManager().get(); _cart = _console->GetCartridge().get(); _spc = _console->GetSpc().get(); - + _gameboy = _cart->GetGameboy(); _ppu = _gameboy->GetPpu(); _control = 0x01; //Divider = 5, gameboy = not running UpdateClockRatio(); - + MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, this); cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, this); } @@ -66,12 +67,16 @@ void SuperGameboy::Reset() uint8_t SuperGameboy::Read(uint32_t addr) { addr &= 0xF80F; - - if(addr >= 0x7000 && addr <= 0x700F) { + + if (addr >= 0x7000 && addr <= 0x700F) + { _packetReady = false; return _packetData[addr & 0x0F]; - } else if(addr >= 0x7800 && addr <= 0x780F) { - if(_readPosition >= 320) { + } + else if (addr >= 0x7800 && addr <= 0x780F) + { + if (_readPosition >= 320) + { //Return 0xFF for 320..511 and then wrap to 0 _readPosition = (_readPosition + 1) & 0x1FF; return 0xFF; @@ -83,16 +88,20 @@ uint8_t SuperGameboy::Read(uint32_t addr) uint8_t data = 0; uint8_t shift = _readPosition & 0x01; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { data |= ((start[i] >> shift) & 0x01) << (7 - i); } _readPosition++; return data; - } else { - switch(addr & 0xFFFF) { - case 0x6000: return (GetLcdRow() << 3) | GetLcdBufferRow(); - case 0x6002: return _packetReady; - case 0x600F: return 0x21; //or 0x61 + } + else + { + switch (addr & 0xFFFF) + { + case 0x6000: return (GetLcdRow() << 3) | GetLcdBufferRow(); + case 0x6002: return _packetReady; + case 0x600F: return 0x21; //or 0x61 } } @@ -103,14 +112,17 @@ void SuperGameboy::Write(uint32_t addr, uint8_t value) { addr &= 0xF80F; - switch(addr & 0xFFFF) { - case 0x6001: - _lcdRowSelect = value & 0x03; - _readPosition = 0; - break; + switch (addr & 0xFFFF) + { + case 0x6001: + _lcdRowSelect = value & 0x03; + _readPosition = 0; + break; - case 0x6003: { - if(!(_control & 0x80) && (value & 0x80)) { + case 0x6003: + { + if (!(_control & 0x80) && (value & 0x80)) + { _resetClock = _memoryManager->GetMasterClock(); _gameboy->PowerOn(this); _ppu = _gameboy->GetPpu(); @@ -122,67 +134,94 @@ void SuperGameboy::Write(uint32_t addr, uint8_t value) break; } - case 0x6004: _input[0] = value; break; - case 0x6005: _input[1] = value; break; - case 0x6006: _input[2] = value; break; - case 0x6007: _input[3] = value; break; + case 0x6004: _input[0] = value; + break; + case 0x6005: _input[1] = value; + break; + case 0x6006: _input[2] = value; + break; + case 0x6007: _input[3] = value; + break; } } void SuperGameboy::ProcessInputPortWrite(uint8_t value) { - if(_inputValue == value) { + if (_inputValue == value) + { return; } - if(value == 0x00) { + if (value == 0x00) + { //Reset pulse _waitForHigh = true; _packetByte = 0; _packetBit = 0; - } else if(_waitForHigh) { - if(value == 0x10 || value == 0x20) { + } + else if (_waitForHigh) + { + if (value == 0x10 || value == 0x20) + { //Invalid sequence (should be 0x00 -> 0x30 -> 0x10/0x20 -> 0x30 -> 0x10/0x20, etc.) _waitForHigh = false; _listeningForPacket = false; - } else if(value == 0x30) { + } + else if (value == 0x30) + { _waitForHigh = false; _listeningForPacket = true; } - } else if(_listeningForPacket) { - if(value == 0x20) { + } + else if (_listeningForPacket) + { + if (value == 0x20) + { //0 bit - if(_packetByte >= 16 && _packetBit == 0) { + if (_packetByte >= 16 && _packetBit == 0) + { _packetReady = true; _listeningForPacket = false; - if(_console->IsDebugging()) { + if (_console->IsDebugging()) + { LogPacket(); } - } else { + } + else + { _packetData[_packetByte] &= ~(1 << _packetBit); } _packetBit++; - if(_packetBit == 8) { + if (_packetBit == 8) + { _packetBit = 0; _packetByte++; } - } else if(value == 0x10) { + } + else if (value == 0x10) + { //1 bit - if(_packetByte >= 16) { + if (_packetByte >= 16) + { //Invalid bit _listeningForPacket = false; - } else { + } + else + { _packetData[_packetByte] |= (1 << _packetBit); _packetBit++; - if(_packetBit == 8) { + if (_packetBit == 8) + { _packetBit = 0; _packetByte++; } } } _waitForHigh = _listeningForPacket; - } else if(!(_inputValue & 0x20) && (value & 0x20)) { + } + else if (!(_inputValue & 0x20) && (value & 0x20)) + { _inputIndex = (_inputIndex + 1) % GetPlayerCount(); } @@ -194,41 +233,72 @@ void SuperGameboy::LogPacket() { uint8_t commandId = _packetData[0] >> 3; string name; - switch(commandId) { - case 0: name = "PAL01"; break; //Set SGB Palette 0, 1 Data - case 1: name = "PAL23"; break; //Set SGB Palette 2, 3 Data - case 2: name = "PAL03"; break; //Set SGB Palette 0, 3 Data - case 3: name = "PAL12"; break; //Set SGB Palette 1, 2 Data - case 4: name = "ATTR_BLK"; break; //"Block" Area Designation Mode - case 5: name = "ATTR_LIN"; break; //"Line" Area Designation Mode - case 6: name = "ATTR_DIV"; break; //"Divide" Area Designation Mode - case 7: name = "ATTR_CHR"; break; //"1CHR" Area Designation Mode - case 8: name = "SOUND"; break; //Sound On / Off - case 9: name = "SOU_TRN"; break; //Transfer Sound PRG / DATA - case 0xA: name = "PAL_SET"; break; //Set SGB Palette Indirect - case 0xB: name = "PAL_TRN"; break; //Set System Color Palette Data - case 0xC: name = "ATRC_EN"; break; //Enable / disable Attraction Mode - case 0xD: name = "TEST_EN"; break; //Speed Function - case 0xE: name = "ICON_EN"; break; //SGB Function - case 0xF: name = "DATA_SND"; break; //SUPER NES WRAM Transfer 1 - case 0x10: name = "DATA_TRN"; break; //SUPER NES WRAM Transfer 2 - case 0x11: name = "MLT_REG"; break; //Controller 2 Request - case 0x12: name = "JUMP"; break; //Set SNES Program Counter - case 0x13: name = "CHR_TRN"; break; //Transfer Character Font Data - case 0x14: name = "PCT_TRN"; break; //Set Screen Data Color Data - case 0x15: name = "ATTR_TRN"; break; //Set Attribute from ATF - case 0x16: name = "ATTR_SET"; break; //Set Data to ATF - case 0x17: name = "MASK_EN"; break; //Game Boy Window Mask - case 0x18: name = "OBJ_TRN"; break; //Super NES OBJ Mode - - case 0x1E: name = "Header Data"; break; - case 0x1F: name = "Header Data"; break; + switch (commandId) + { + case 0: name = "PAL01"; + break; //Set SGB Palette 0, 1 Data + case 1: name = "PAL23"; + break; //Set SGB Palette 2, 3 Data + case 2: name = "PAL03"; + break; //Set SGB Palette 0, 3 Data + case 3: name = "PAL12"; + break; //Set SGB Palette 1, 2 Data + case 4: name = "ATTR_BLK"; + break; //"Block" Area Designation Mode + case 5: name = "ATTR_LIN"; + break; //"Line" Area Designation Mode + case 6: name = "ATTR_DIV"; + break; //"Divide" Area Designation Mode + case 7: name = "ATTR_CHR"; + break; //"1CHR" Area Designation Mode + case 8: name = "SOUND"; + break; //Sound On / Off + case 9: name = "SOU_TRN"; + break; //Transfer Sound PRG / DATA + case 0xA: name = "PAL_SET"; + break; //Set SGB Palette Indirect + case 0xB: name = "PAL_TRN"; + break; //Set System Color Palette Data + case 0xC: name = "ATRC_EN"; + break; //Enable / disable Attraction Mode + case 0xD: name = "TEST_EN"; + break; //Speed Function + case 0xE: name = "ICON_EN"; + break; //SGB Function + case 0xF: name = "DATA_SND"; + break; //SUPER NES WRAM Transfer 1 + case 0x10: name = "DATA_TRN"; + break; //SUPER NES WRAM Transfer 2 + case 0x11: name = "MLT_REG"; + break; //Controller 2 Request + case 0x12: name = "JUMP"; + break; //Set SNES Program Counter + case 0x13: name = "CHR_TRN"; + break; //Transfer Character Font Data + case 0x14: name = "PCT_TRN"; + break; //Set Screen Data Color Data + case 0x15: name = "ATTR_TRN"; + break; //Set Attribute from ATF + case 0x16: name = "ATTR_SET"; + break; //Set Data to ATF + case 0x17: name = "MASK_EN"; + break; //Game Boy Window Mask + case 0x18: name = "OBJ_TRN"; + break; //Super NES OBJ Mode - default: name = "Unknown"; break; + case 0x1E: name = "Header Data"; + break; + case 0x1F: name = "Header Data"; + break; + + default: name = "Unknown"; + break; } - string log = "SGB Command: " + HexUtilities::ToHex(commandId) + " - " + name + " (Len: " + std::to_string(_packetData[0] & 0x07) + ") - "; - for(int i = 0; i < 16; i++) { + string log = "SGB Command: " + HexUtilities::ToHex(commandId) + " - " + name + " (Len: " + std::to_string( + _packetData[0] & 0x07) + ") - "; + for (int i = 0; i < 16; i++) + { log += HexUtilities::ToHex(_packetData[i]) + " "; } _console->DebugLog(log); @@ -243,7 +313,8 @@ uint8_t SuperGameboy::GetLcdRow() { uint8_t scanline = _ppu->GetScanline(); uint8_t row = scanline / 8; - if(row >= 18) { + if (row >= 18) + { row = 0; } return row; @@ -257,7 +328,8 @@ uint8_t SuperGameboy::GetLcdBufferRow() uint8_t SuperGameboy::GetPlayerCount() { uint8_t playerCount = ((_control >> 4) & 0x03) + 1; - if(playerCount >= 3) { + if (playerCount >= 3) + { //Unknown: 2 and 3 both mean 4 players? return 4; } @@ -270,29 +342,35 @@ void SuperGameboy::MixAudio(uint32_t targetRate, int16_t* soundSamples, uint32_t uint32_t gbSampleCount = 0; _gameboy->GetSoundSamples(gbSamples, gbSampleCount); _resampler.SetSampleRates(GbApu::SampleRate, targetRate); - + int32_t outCount = (int32_t)_resampler.Resample(gbSamples, gbSampleCount, _mixBuffer + _mixSampleCount) * 2; _mixSampleCount += outCount; - int32_t copyCount = (int32_t)std::min(_mixSampleCount, sampleCount*2); - if(!_spc->IsMuted()) { - for(int32_t i = 0; i < copyCount; i++) { + int32_t copyCount = (int32_t)std::min(_mixSampleCount, sampleCount * 2); + if (!_spc->IsMuted()) + { + for (int32_t i = 0; i < copyCount; i++) + { soundSamples[i] += _mixBuffer[i]; } } int32_t remainingSamples = (int32_t)_mixSampleCount - copyCount; - if(remainingSamples > 0) { - memmove(_mixBuffer, _mixBuffer + copyCount, remainingSamples*sizeof(int16_t)); + if (remainingSamples > 0) + { + memmove(_mixBuffer, _mixBuffer + copyCount, remainingSamples * sizeof(int16_t)); _mixSampleCount = remainingSamples; - } else { + } + else + { _mixSampleCount = 0; } } void SuperGameboy::Run() { - if(!(_control & 0x80)) { + if (!(_control & 0x80)) + { return; } @@ -306,11 +384,16 @@ void SuperGameboy::UpdateClockRatio() uint8_t divider = 5; //TODO: This doesn't actually work properly if the speed is changed while the SGB is running (but this most likely never happens?) - switch(_control & 0x03) { - case 0: divider = 4; break; - case 1: divider = 5; break; - case 2: divider = 7; break; - case 3: divider = 9; break; + switch (_control & 0x03) + { + case 0: divider = 4; + break; + case 1: divider = 5; + break; + case 2: divider = 7; + break; + case 3: divider = 9; + break; } double effectiveRate = (double)masterRate / divider; @@ -344,7 +427,7 @@ void SuperGameboy::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo SuperGameboy::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void SuperGameboy::Serialize(Serializer& s) diff --git a/Core/SuperGameboy.h b/Core/SuperGameboy.h index f7766e9..3b89e23 100644 --- a/Core/SuperGameboy.h +++ b/Core/SuperGameboy.h @@ -23,7 +23,7 @@ private: uint8_t _control = 0; uint64_t _resetClock = 0; double _clockRatio = 0; - + uint8_t _input[4] = {}; uint8_t _inputIndex = 0; @@ -31,7 +31,7 @@ private: bool _waitForHigh = true; bool _packetReady = false; uint64_t _inputWriteClock = 0; - uint8_t _inputValue = 0; + uint8_t _inputValue = 0; uint8_t _packetData[16] = {}; uint8_t _packetByte = 0; uint8_t _packetBit = 0; @@ -39,7 +39,7 @@ private: uint8_t _lcdRowSelect = 0; uint16_t _readPosition = 0; uint8_t _lcdBuffer[4][1280] = {}; - + HermiteResampler _resampler; int16_t* _mixBuffer = nullptr; uint32_t _mixSampleCount = 0; @@ -53,7 +53,7 @@ public: ~SuperGameboy(); void Reset() override; - + uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; @@ -77,4 +77,4 @@ public: void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SuperScope.h b/Core/SuperScope.h index f559a7e..0c80fcb 100644 --- a/Core/SuperScope.h +++ b/Core/SuperScope.h @@ -9,16 +9,17 @@ class SuperScope : public BaseControlDevice { private: enum Buttons { Fire = 0, Cursor = 1, Turbo = 2, Pause = 3 }; + uint32_t _stateBuffer = 0; bool _prevFireButton = false; bool _prevTurboButton = false; bool _prevPauseButton = false; bool _turbo = false; - Ppu *_ppu; + Ppu* _ppu; protected: bool HasCoordinates() override { return true; } - + string GetKeyNames() override { return "FCTP"; @@ -29,7 +30,8 @@ protected: SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton)); SetPressedState(Buttons::Cursor, KeyManager::IsMouseButtonPressed(MouseButton::RightButton)); SetPressedState(Buttons::Turbo, KeyManager::IsMouseButtonPressed(MouseButton::MiddleButton)); - for(KeyMapping keyMapping : _keyMappings) { + for (KeyMapping keyMapping : _keyMappings) + { SetPressedState(Buttons::Pause, KeyManager::IsKeyPressed(keyMapping.Start)); } @@ -42,12 +44,13 @@ protected: MousePosition pos = GetCoordinates(); //Make the PPU latch the H/V counters at the mouse's position (offset slightly to make target in the center of the mouse cursor) - if(pos.X >= 0 && pos.Y >= 0) { + if (pos.X >= 0 && pos.Y >= 0) + { _ppu->SetLocationLatchRequest(pos.X + 10, std::max(0, pos.Y - 3)); } } - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer, _prevTurboButton, _prevFireButton, _prevPauseButton, _turbo); @@ -65,27 +68,33 @@ protected: { uint16_t output = 0xFF00; //signature bits - if(!_prevTurboButton && IsPressed(Buttons::Turbo)) { + if (!_prevTurboButton && IsPressed(Buttons::Turbo)) + { _turbo = !_turbo; } - if((_turbo || !_prevFireButton) && IsPressed(Buttons::Fire)) { + if ((_turbo || !_prevFireButton) && IsPressed(Buttons::Fire)) + { output |= 0x01; } - if(IsPressed(Buttons::Cursor)) { + if (IsPressed(Buttons::Cursor)) + { output |= 0x02; } - if(_turbo) { + if (_turbo) + { output |= 0x04; } - if(!_prevPauseButton && IsPressed(Buttons::Pause)) { + if (!_prevPauseButton && IsPressed(Buttons::Pause)) + { output |= 0x08; } - if(GetCoordinates().X < 0 || GetCoordinates().Y < 0) { + if (GetCoordinates().X < 0 || GetCoordinates().Y < 0) + { output |= 0x40; //offscreen flag } @@ -107,7 +116,8 @@ public: { uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); output = (_stateBuffer & 0x01); @@ -123,4 +133,4 @@ public: { StrobeProcessWrite(value); } -}; \ No newline at end of file +}; diff --git a/Core/SystemActionManager.h b/Core/SystemActionManager.h index c5e42cc..6359de8 100644 --- a/Core/SystemActionManager.h +++ b/Core/SystemActionManager.h @@ -15,7 +15,7 @@ protected: { return "RP"; } - + public: enum Buttons { ResetButton = 0, PowerButton = 1 }; @@ -39,19 +39,23 @@ public: void OnAfterSetState() override { - if(_needReset) { + if (_needReset) + { SetBit(SystemActionManager::Buttons::ResetButton); } - if(_needPowerCycle) { + if (_needPowerCycle) + { SetBit(SystemActionManager::Buttons::PowerButton); } } bool Reset() { - if(!_needReset) { + if (!_needReset) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); debugger->Run(); } @@ -64,9 +68,11 @@ public: bool PowerCycle() { - if(!_needPowerCycle) { + if (!_needPowerCycle) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); debugger->Run(); } @@ -88,4 +94,4 @@ public: _needPowerCycle = false; return IsPressed(SystemActionManager::Buttons::PowerButton); } -}; \ No newline at end of file +}; diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index dc4c827..ef1b989 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -48,21 +48,23 @@ TraceLogger::~TraceLogger() delete[] _logCpuTypeCopy; } -template -void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart) +template +void TraceLogger::WriteValue(string& output, T value, RowPart& rowPart) { string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value); output += str; - if(rowPart.MinWidth > (int)str.size()) { + if (rowPart.MinWidth > (int)str.size()) + { output += std::string(rowPart.MinWidth - str.size(), ' '); } } -template<> -void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart) +template <> +void TraceLogger::WriteValue(string& output, string value, RowPart& rowPart) { output += value; - if(rowPart.MinWidth > (int)value.size()) { + if (rowPart.MinWidth > (int)value.size()) + { output += std::string(rowPart.MinWidth - value.size(), ' '); } } @@ -70,7 +72,7 @@ void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart) void TraceLogger::SetOptions(TraceLoggerOptions options) { _options = options; - + _logCpu[(int)CpuType::Cpu] = options.LogCpu; _logCpu[(int)CpuType::Spc] = options.LogSpc; _logCpu[(int)CpuType::NecDsp] = options.LogNecDsp; @@ -93,92 +95,157 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) }*/ ParseFormatString(_rowParts, format); - ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_gsuRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_cx4RowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] [A,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_gbRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] HL:[H,2h][L,2h] F:[F,2h] SP:[SP,4h] CYC:[Cycle,3] LY:[Scanline,3]"); + ParseFormatString(_spcRowParts, + "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_dspRowParts, + "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_gsuRowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_cx4RowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] [A,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_gbRowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] HL:[H,2h][L,2h] F:[F,2h] SP:[SP,4h] CYC:[Cycle,3] LY:[Scanline,3]"); } -void TraceLogger::ParseFormatString(vector &rowParts, string format) +void TraceLogger::ParseFormatString(vector& rowParts, string format) { rowParts.clear(); - std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", std::regex_constants::icase); + std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", + std::regex_constants::icase); std::sregex_iterator start = std::sregex_iterator(format.cbegin(), format.cend(), formatRegex); std::sregex_iterator end = std::sregex_iterator(); - for(std::sregex_iterator it = start; it != end; it++) { + for (std::sregex_iterator it = start; it != end; it++) + { const std::smatch& match = *it; - if(match.str(1) == "") { + if (match.str(1) == "") + { RowPart part = {}; part.DataType = RowDataType::Text; part.Text = match.str(6); rowParts.push_back(part); - } else { + } + else + { RowPart part = {}; string dataType = match.str(2); - if(dataType == "ByteCode") { + if (dataType == "ByteCode") + { part.DataType = RowDataType::ByteCode; - } else if(dataType == "Disassembly") { + } + else if (dataType == "Disassembly") + { part.DataType = RowDataType::Disassembly; - } else if(dataType == "EffectiveAddress") { + } + else if (dataType == "EffectiveAddress") + { part.DataType = RowDataType::EffectiveAddress; - } else if(dataType == "MemoryValue") { + } + else if (dataType == "MemoryValue") + { part.DataType = RowDataType::MemoryValue; - } else if(dataType == "Align") { + } + else if (dataType == "Align") + { part.DataType = RowDataType::Align; - } else if(dataType == "PC") { + } + else if (dataType == "PC") + { part.DataType = RowDataType::PC; - } else if(dataType == "A") { + } + else if (dataType == "A") + { part.DataType = RowDataType::A; - } else if(dataType == "B") { + } + else if (dataType == "B") + { part.DataType = RowDataType::B; - } else if(dataType == "C") { + } + else if (dataType == "C") + { part.DataType = RowDataType::C; - } else if(dataType == "D") { + } + else if (dataType == "D") + { part.DataType = RowDataType::D; - } else if(dataType == "E") { + } + else if (dataType == "E") + { part.DataType = RowDataType::E; - } else if(dataType == "F") { + } + else if (dataType == "F") + { part.DataType = RowDataType::F; - } else if(dataType == "H") { + } + else if (dataType == "H") + { part.DataType = RowDataType::H; - } else if(dataType == "L") { + } + else if (dataType == "L") + { part.DataType = RowDataType::L; - } else if(dataType == "X") { + } + else if (dataType == "X") + { part.DataType = RowDataType::X; - } else if(dataType == "Y") { + } + else if (dataType == "Y") + { part.DataType = RowDataType::Y; - } else if(dataType == "D") { + } + else if (dataType == "D") + { part.DataType = RowDataType::D; - } else if(dataType == "DB") { + } + else if (dataType == "DB") + { part.DataType = RowDataType::DB; - } else if(dataType == "P") { + } + else if (dataType == "P") + { part.DataType = RowDataType::PS; - } else if(dataType == "SP") { + } + else if (dataType == "SP") + { part.DataType = RowDataType::SP; - } else if(dataType == "Cycle") { + } + else if (dataType == "Cycle") + { part.DataType = RowDataType::Cycle; - } else if(dataType == "HClock") { + } + else if (dataType == "HClock") + { part.DataType = RowDataType::HClock; - } else if(dataType == "Scanline") { + } + else if (dataType == "Scanline") + { part.DataType = RowDataType::Scanline; - } else if(dataType == "FrameCount") { + } + else if (dataType == "FrameCount") + { part.DataType = RowDataType::FrameCount; - } else if(dataType == "CycleCount") { + } + else if (dataType == "CycleCount") + { part.DataType = RowDataType::CycleCount; - } else { + } + else + { part.DataType = RowDataType::Text; part.Text = "[Invalid tag]"; } - if(!match.str(4).empty()) { - try { + if (!match.str(4).empty()) + { + try + { part.MinWidth = std::stoi(match.str(4)); - } catch(std::exception&) { + } + catch (std::exception&) + { } } part.DisplayInHex = match.str(5) == "h"; @@ -197,10 +264,13 @@ void TraceLogger::StartLogging(string filename) void TraceLogger::StopLogging() { - if(_logToFile) { + if (_logToFile) + { _logToFile = false; - if(_outputFile) { - if(!_outputBuffer.empty()) { + if (_outputFile) + { + if (!_outputBuffer.empty()) + { _outputFile << _outputBuffer; } _outputFile.close(); @@ -208,36 +278,45 @@ void TraceLogger::StopLogging() } } -void TraceLogger::LogExtraInfo(const char *log, uint32_t cycleCount) +void TraceLogger::LogExtraInfo(const char* log, uint32_t cycleCount) { - if(_logToFile && _options.ShowExtraInfo) { + if (_logToFile && _options.ShowExtraInfo) + { //Flush current buffer _outputFile << _outputBuffer; _outputBuffer.clear(); - _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << (_options.UseWindowsEol ? "\r\n" : "\n"); + _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << ( + _options.UseWindowsEol ? "\r\n" : "\n"); } } -template -void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part) +template +void TraceLogger::GetStatusFlag(string& output, uint8_t ps, RowPart& part) { - constexpr char cpuActiveStatusLetters[8] = { 'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C' }; - constexpr char cpuInactiveStatusLetters[8] = { 'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c' }; + constexpr char cpuActiveStatusLetters[8] = {'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C'}; + constexpr char cpuInactiveStatusLetters[8] = {'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c'}; - constexpr char spcActiveStatusLetters[8] = { 'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C' }; - constexpr char spcInactiveStatusLetters[8] = { 'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c' }; + constexpr char spcActiveStatusLetters[8] = {'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C'}; + constexpr char spcInactiveStatusLetters[8] = {'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c'}; - const char *activeStatusLetters = cpuType == CpuType::Cpu ? cpuActiveStatusLetters : spcActiveStatusLetters; - const char *inactiveStatusLetters = cpuType == CpuType::Cpu ? cpuInactiveStatusLetters : spcInactiveStatusLetters; + const char* activeStatusLetters = cpuType == CpuType::Cpu ? cpuActiveStatusLetters : spcActiveStatusLetters; + const char* inactiveStatusLetters = cpuType == CpuType::Cpu ? cpuInactiveStatusLetters : spcInactiveStatusLetters; - if(part.DisplayInHex) { + if (part.DisplayInHex) + { WriteValue(output, ps, part); - } else { + } + else + { string flags; - for(int i = 0; i < 8; i++) { - if(ps & 0x80) { + for (int i = 0; i < 8; i++) + { + if (ps & 0x80) + { flags += activeStatusLetters[i]; - } else if(part.MinWidth >= 8) { + } + else if (part.MinWidth >= 8) + { flags += inactiveStatusLetters[i]; } ps <<= 1; @@ -246,23 +325,25 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part) } } -void TraceLogger::WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output) +void TraceLogger::WriteByteCode(DisassemblyInfo& info, RowPart& rowPart, string& output) { string byteCode; info.GetByteCode(byteCode); - if(!rowPart.DisplayInHex) { + if (!rowPart.DisplayInHex) + { //Remove $ marks if not in "hex" mode (but still display the bytes as hex) byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end()); } WriteValue(output, byteCode, rowPart); } -void TraceLogger::WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output) +void TraceLogger::WriteDisassembly(DisassemblyInfo& info, RowPart& rowPart, uint8_t sp, uint32_t pc, string& output) { int indentLevel = 0; string code; - if(_options.IndentCode) { + if (_options.IndentCode) + { indentLevel = 0xFF - (sp & 0xFF); code = std::string(indentLevel, ' '); } @@ -272,14 +353,18 @@ void TraceLogger::WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint WriteValue(output, code, rowPart); } -void TraceLogger::WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType) +void TraceLogger::WriteEffectiveAddress(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType cpuMemoryType, CpuType cpuType) { int32_t effectiveAddress = info.GetEffectiveAddress(_console, cpuState, cpuType); - if(effectiveAddress >= 0) { - if(_options.UseLabels) { - AddressInfo addr { effectiveAddress, cpuMemoryType }; + if (effectiveAddress >= 0) + { + if (_options.UseLabels) + { + AddressInfo addr{effectiveAddress, cpuMemoryType}; string label = _labelManager->GetLabel(addr); - if(!label.empty()) { + if (!label.empty()) + { WriteValue(output, " [" + label + "]", rowPart); return; } @@ -288,231 +373,349 @@ void TraceLogger::WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, } } -void TraceLogger::WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType) +void TraceLogger::WriteMemoryValue(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType memType, CpuType cpuType) { int32_t address = info.GetEffectiveAddress(_console, cpuState, cpuType); - if(address >= 0) { + if (address >= 0) + { uint8_t valueSize; uint16_t value = info.GetMemoryValue(address, _memoryDumper, memType, valueSize); - if(rowPart.DisplayInHex) { + if (rowPart.DisplayInHex) + { output += "= $"; - if(valueSize == 2) { + if (valueSize == 2) + { WriteValue(output, (uint16_t)value, rowPart); - } else { + } + else + { WriteValue(output, (uint8_t)value, rowPart); } - } else { + } + else + { output += "= "; } } } -void TraceLogger::WriteAlign(int originalSize, RowPart &rowPart, string &output) +void TraceLogger::WriteAlign(int originalSize, RowPart& rowPart, string& output) { - if((int)output.size() - originalSize < rowPart.MinWidth) { + if ((int)output.size() - originalSize < rowPart.MinWidth) + { output += std::string(rowPart.MinWidth - (output.size() - originalSize), ' '); } } -void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType) +void TraceLogger::GetTraceRow(string& output, CpuState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo, + SnesMemoryType memType, CpuType cpuType) { int originalSize = (int)output.size(); uint32_t pcAddress = (cpuState.K << 16) | cpuState.PC; - for(RowPart& rowPart : _rowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _rowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: + WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, memType, + cpuType); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break; - case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break; - case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break; - case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); break; - default: break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::X: WriteValue(output, cpuState.X, rowPart); + break; + case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); + break; + case RowDataType::D: WriteValue(output, cpuState.D, rowPart); + break; + case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, SpcState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _spcRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _spcRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::SpcMemory, CpuType::Spc); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::SpcMemory, CpuType::Spc); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break; - case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::X: WriteValue(output, cpuState.X, rowPart); + break; + case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; - default: break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, NecDspState& cpuState, PpuState& ppuState, + DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _dspRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _dspRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: - output += "A:" + HexUtilities::ToHex(cpuState.A); - output += " B:" + HexUtilities::ToHex(cpuState.B); - output += " DR:" + HexUtilities::ToHex(cpuState.DR); - output += " DP:" + HexUtilities::ToHex(cpuState.DP); - output += " SR:" + HexUtilities::ToHex(cpuState.SR); - output += " K:" + HexUtilities::ToHex(cpuState.K); - output += " L:" + HexUtilities::ToHex(cpuState.L); - output += " M:" + HexUtilities::ToHex(cpuState.M); - output += " N:" + HexUtilities::ToHex(cpuState.N); - output += " RP:" + HexUtilities::ToHex(cpuState.RP); - output += " TR:" + HexUtilities::ToHex(cpuState.TR); - output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " "; - //output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA); - //output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB); - WriteValue(output, cpuState.A, rowPart); - break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: + output += "A:" + HexUtilities::ToHex(cpuState.A); + output += " B:" + HexUtilities::ToHex(cpuState.B); + output += " DR:" + HexUtilities::ToHex(cpuState.DR); + output += " DP:" + HexUtilities::ToHex(cpuState.DP); + output += " SR:" + HexUtilities::ToHex(cpuState.SR); + output += " K:" + HexUtilities::ToHex(cpuState.K); + output += " L:" + HexUtilities::ToHex(cpuState.L); + output += " M:" + HexUtilities::ToHex(cpuState.M); + output += " N:" + HexUtilities::ToHex(cpuState.N); + output += " RP:" + HexUtilities::ToHex(cpuState.RP); + output += " TR:" + HexUtilities::ToHex(cpuState.TR); + output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " "; + //output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA); + //output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB); + WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, GsuState& gsuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = (gsuState.ProgramBank << 16) | gsuState.R[15]; - for(RowPart& rowPart : _gsuRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _gsuRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: - WriteValue(output, gsuState.R[0], rowPart); - for(int i = 1; i < 16; i++) { - output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]); - } - break; - case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); break; - case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: + WriteValue(output, gsuState.R[0], rowPart); + for (int i = 1; i < 16; i++) + { + output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]); + } + break; + case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); + break; + case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); + break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, Cx4State &cx4State, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, Cx4State& cx4State, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = (cx4State.Cache.Address[cx4State.Cache.Page] + (cx4State.PC * 2)) & 0xFFFFFF; - for(RowPart& rowPart : _cx4RowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _cx4RowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: - output += " A:" + HexUtilities::ToHex24(cx4State.A); - output += string(" ") + (cx4State.Carry ? "C" : "c") + (cx4State.Zero ? "Z" : "z") + (cx4State.Overflow ? "V" : "v") + (cx4State.Negative ? "N" : "n"); + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: + output += " A:" + HexUtilities::ToHex24(cx4State.A); + output += string(" ") + (cx4State.Carry ? "C" : "c") + (cx4State.Zero ? "Z" : "z") + ( + cx4State.Overflow ? "V" : "v") + (cx4State.Negative ? "N" : "n"); - output += " PC:" + HexUtilities::ToHex(cx4State.PC); - output += " MAR:" + HexUtilities::ToHex24(cx4State.MemoryAddressReg); - output += " MDR:" + HexUtilities::ToHex24(cx4State.MemoryDataReg); - output += " DPR:" + HexUtilities::ToHex24(cx4State.DataPointerReg); - output += " ML:" + HexUtilities::ToHex24((uint32_t)cx4State.Mult & 0xFFFFFF); - output += " MH:" + HexUtilities::ToHex24((uint32_t)(cx4State.Mult >> 24) & 0xFFFFFF); - for(int i = 0; i < 16; i++) { - output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex24(cx4State.Regs[i]); - } - break; + output += " PC:" + HexUtilities::ToHex(cx4State.PC); + output += " MAR:" + HexUtilities::ToHex24(cx4State.MemoryAddressReg); + output += " MDR:" + HexUtilities::ToHex24(cx4State.MemoryDataReg); + output += " DPR:" + HexUtilities::ToHex24(cx4State.DataPointerReg); + output += " ML:" + HexUtilities::ToHex24((uint32_t)cx4State.Mult & 0xFFFFFF); + output += " MH:" + HexUtilities::ToHex24((uint32_t)(cx4State.Mult >> 24) & 0xFFFFFF); + for (int i = 0; i < 16; i++) + { + output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex24(cx4State.Regs[i]); + } + break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string& output, GbCpuState& cpuState, GbPpuState& ppuState, DisassemblyInfo& disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, GbCpuState& cpuState, GbPpuState& ppuState, + DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _gbRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _gbRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: + WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::GameboyMemory, CpuType::Gameboy); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::GameboyMemory, CpuType::Gameboy); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::B: WriteValue(output, cpuState.B, rowPart); break; - case RowDataType::C: WriteValue(output, cpuState.C, rowPart); break; - case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break; - case RowDataType::E: WriteValue(output, cpuState.E, rowPart); break; - case RowDataType::F: WriteValue(output, cpuState.Flags, rowPart); break; - case RowDataType::H: WriteValue(output, cpuState.H, rowPart); break; - case RowDataType::L: WriteValue(output, cpuState.L, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::B: WriteValue(output, cpuState.B, rowPart); + break; + case RowDataType::C: WriteValue(output, cpuState.C, rowPart); + break; + case RowDataType::D: WriteValue(output, cpuState.D, rowPart); + break; + case RowDataType::E: WriteValue(output, cpuState.E, rowPart); + break; + case RowDataType::F: WriteValue(output, cpuState.Flags, rowPart); + break; + case RowDataType::H: WriteValue(output, cpuState.H, rowPart); + break; + case RowDataType::L: WriteValue(output, cpuState.L, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; - default: break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; @@ -537,33 +740,45 @@ bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemb } */ -void TraceLogger::GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state) +void TraceLogger::GetTraceRow(string& output, CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state) { - switch(cpuType) { - case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::CpuMemory, cpuType); break; - case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); break; - case CpuType::NecDsp: GetTraceRow(output, state.NecDsp, state.Ppu, disassemblyInfo); break; - case CpuType::Sa1: GetTraceRow(output, state.Sa1.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory, cpuType); break; - case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); break; - case CpuType::Cx4: GetTraceRow(output, state.Cx4, state.Ppu, disassemblyInfo); break; - case CpuType::Gameboy: GetTraceRow(output, state.Gameboy.Cpu, state.Gameboy.Ppu, disassemblyInfo); break; + switch (cpuType) + { + case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::CpuMemory, cpuType); + break; + case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); + break; + case CpuType::NecDsp: GetTraceRow(output, state.NecDsp, state.Ppu, disassemblyInfo); + break; + case CpuType::Sa1: GetTraceRow(output, state.Sa1.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory, + cpuType); + break; + case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); + break; + case CpuType::Cx4: GetTraceRow(output, state.Cx4, state.Ppu, disassemblyInfo); + break; + case CpuType::Gameboy: GetTraceRow(output, state.Gameboy.Cpu, state.Gameboy.Ppu, disassemblyInfo); + break; } } -void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state) +void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state) { _logCpuType[_currentPos] = cpuType; _disassemblyCache[_currentPos] = disassemblyInfo; _stateCache[_currentPos] = state; _pendingLog = false; - if(_logCount < ExecutionLogSize) { + if (_logCount < ExecutionLogSize) + { _logCount++; } - if(_logToFile) { + if (_logToFile) + { GetTraceRow(_outputBuffer, cpuType, _disassemblyCache[_currentPos], _stateCache[_currentPos]); - if(_outputBuffer.size() > 32768) { + if (_outputBuffer.size() > 32768) + { _outputFile << _outputBuffer; _outputBuffer.clear(); } @@ -571,6 +786,7 @@ void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, Debu _currentPos = (_currentPos + 1) % ExecutionLogSize; } + /* void TraceLogger::LogNonExec(OperationInfo& operationInfo) { @@ -582,13 +798,14 @@ void TraceLogger::LogNonExec(OperationInfo& operationInfo) } }*/ -void TraceLogger::Log(CpuType cpuType, DebugState &state, DisassemblyInfo &disassemblyInfo) +void TraceLogger::Log(CpuType cpuType, DebugState& state, DisassemblyInfo& disassemblyInfo) { - if(_logCpu[(int)cpuType]) { + if (_logCpu[(int)cpuType]) + { //For the sake of performance, only log data for the CPUs we're actively displaying/logging auto lock = _lock.AcquireSafe(); //if(ConditionMatches(state, disassemblyInfo, operationInfo)) { - AddRow(cpuType, disassemblyInfo, state); + AddRow(cpuType, disassemblyInfo, state); //} } } @@ -613,37 +830,55 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) } bool enabled = false; - for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) { + for (int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) + { enabled |= _logCpu[i]; } - if(enabled && lineCount > 0) { - for(int i = 0; i < TraceLogger::ExecutionLogSize; i++) { + if (enabled && lineCount > 0) + { + for (int i = 0; i < TraceLogger::ExecutionLogSize; i++) + { int index = (startPos - i); - if(index < 0) { + if (index < 0) + { index = TraceLogger::ExecutionLogSize + index; } - if((i > 0 && startPos == index) || !_disassemblyCacheCopy[index].IsInitialized()) { + if ((i > 0 && startPos == index) || !_disassemblyCacheCopy[index].IsInitialized()) + { //If the entire array was checked, or this element is not initialized, stop break; } CpuType cpuType = _logCpuTypeCopy[index]; - if(!_logCpu[(int)cpuType]) { + if (!_logCpu[(int)cpuType]) + { //This line isn't for a CPU currently being logged continue; } - DebugState &state = _stateCacheCopy[index]; - switch(cpuType) { - case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((state.Cpu.K << 16) | state.Cpu.PC) + "\x1"; break; - case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(state.Spc.PC) + "\x1"; break; - case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.NecDsp.PC) + "\x1"; break; - case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Sa1.Cpu.K << 16) | state.Sa1.Cpu.PC) + "\x1"; break; - case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Gsu.ProgramBank << 16) | state.Gsu.R[15]) + "\x1"; break; - case CpuType::Cx4: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Cx4.Cache.Address[state.Cx4.Cache.Page] + (state.Cx4.PC * 2)) & 0xFFFFFF) + "\x1"; break; - case CpuType::Gameboy: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.Gameboy.Cpu.PC) + "\x1"; break; + DebugState& state = _stateCacheCopy[index]; + switch (cpuType) + { + case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((state.Cpu.K << 16) | state.Cpu.PC) + + "\x1"; + break; + case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(state.Spc.PC) + "\x1"; + break; + case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.NecDsp.PC) + "\x1"; + break; + case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Sa1.Cpu.K << 16) | state.Sa1.Cpu.PC) + "\x1"; + break; + case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Gsu.ProgramBank << 16) | state.Gsu.R[15]) + "\x1"; + break; + case CpuType::Cx4: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Cx4.Cache.Address[state.Cx4.Cache.Page] + (state.Cx4.PC * 2)) & 0xFFFFFF) + "\x1"; + break; + case CpuType::Gameboy: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.Gameboy.Cpu.PC) + "\x1"; + break; } string byteCode; @@ -652,10 +887,11 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) GetTraceRow(_executionTrace, cpuType, _disassemblyCacheCopy[index], _stateCacheCopy[index]); lineCount--; - if(lineCount == 0) { + if (lineCount == 0) + { break; } } } return _executionTrace.c_str(); -} \ No newline at end of file +} diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index 5558019..0269be3 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -106,37 +106,42 @@ private: bool _logToFile; uint32_t _currentPos; uint32_t _logCount; - DebugState *_stateCache = nullptr; - DisassemblyInfo *_disassemblyCache = nullptr; + DebugState* _stateCache = nullptr; + DisassemblyInfo* _disassemblyCache = nullptr; CpuType* _logCpuType = nullptr; - DebugState *_stateCacheCopy = nullptr; - DisassemblyInfo *_disassemblyCacheCopy = nullptr; + DebugState* _stateCacheCopy = nullptr; + DisassemblyInfo* _disassemblyCacheCopy = nullptr; CpuType* _logCpuTypeCopy = nullptr; SimpleLock _lock; - template void GetStatusFlag(string &output, uint8_t ps, RowPart& part); + template + void GetStatusFlag(string& output, uint8_t ps, RowPart& part); - void WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output); - void WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output); - void WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType); - void WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType); - void WriteAlign(int originalSize, RowPart &rowPart, string &output); - void AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state); + void WriteByteCode(DisassemblyInfo& info, RowPart& rowPart, string& output); + void WriteDisassembly(DisassemblyInfo& info, RowPart& rowPart, uint8_t sp, uint32_t pc, string& output); + void WriteEffectiveAddress(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType cpuMemoryType, CpuType cpuType); + void WriteMemoryValue(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType memType, CpuType cpuType); + void WriteAlign(int originalSize, RowPart& rowPart, string& output); + void AddRow(CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state); //bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo); - - void ParseFormatString(vector &rowParts, string format); - void GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state); - void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType); - void GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); - void GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); - void GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); + void ParseFormatString(vector& rowParts, string format); + + void GetTraceRow(string& output, CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state); + void GetTraceRow(string& output, CpuState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo, + SnesMemoryType memType, CpuType cpuType); + void GetTraceRow(string& output, SpcState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); + void GetTraceRow(string& output, NecDspState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); + void GetTraceRow(string& output, GsuState& gsuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); void GetTraceRow(string& output, Cx4State& cx4State, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); - void GetTraceRow(string &output, GbCpuState &gbState, GbPpuState &gbPpuState, DisassemblyInfo &disassemblyInfo); + void GetTraceRow(string& output, GbCpuState& gbState, GbPpuState& gbPpuState, DisassemblyInfo& disassemblyInfo); - template void WriteValue(string &output, T value, RowPart& rowPart); + template + void WriteValue(string& output, T value, RowPart& rowPart); public: TraceLogger(Debugger* debugger, shared_ptr console); @@ -144,14 +149,14 @@ public: __forceinline bool IsCpuLogged(CpuType type) { return _logCpu[(int)type]; } - void Log(CpuType cpuType, DebugState &state, DisassemblyInfo &disassemblyInfo); + void Log(CpuType cpuType, DebugState& state, DisassemblyInfo& disassemblyInfo); void Clear(); //void LogNonExec(OperationInfo& operationInfo); void SetOptions(TraceLoggerOptions options); void StartLogging(string filename); void StopLogging(); - void LogExtraInfo(const char *log, uint32_t cycleCount); + void LogExtraInfo(const char* log, uint32_t cycleCount); const char* GetExecutionTrace(uint32_t lineCount); }; diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 91dbc4a..0b86dde 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -19,7 +19,7 @@ VideoDecoder::VideoDecoder(shared_ptr console) _console = console; _frameChanged = false; _stopFlag = false; - _baseFrameInfo = { 512, 478 }; + _baseFrameInfo = {512, 478}; _lastFrameInfo = _baseFrameInfo; UpdateVideoFilter(); _videoFilter->SetBaseFrameInfo(_baseFrameInfo); @@ -49,14 +49,19 @@ ScreenSize VideoDecoder::GetScreenSize(bool ignoreScale) size.Scale = scale; double aspectRatio = _console->GetSettings()->GetAspectRatio(_console->GetRegion()); - if(aspectRatio != 0.0) { + if (aspectRatio != 0.0) + { VideoAspectRatio aspect = _console->GetSettings()->GetVideoConfig().AspectRatio; - bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == VideoAspectRatio::Auto; - if(usePar) { + bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == + VideoAspectRatio::Auto; + if (usePar) + { OverscanDimensions overscan = _console->GetSettings()->GetOverscan(); uint32_t fullWidth = frameInfo.Width + (overscan.Left + overscan.Right); size.Width = (uint32_t)(256 * scale * aspectRatio * frameInfo.Width / fullWidth); - } else { + } + else + { size.Width = (uint32_t)(size.Height * aspectRatio); } } @@ -68,15 +73,19 @@ void VideoDecoder::UpdateVideoFilter() { VideoFilterType newFilter = _console->GetSettings()->GetVideoConfig().VideoFilter; - if(_videoFilterType != newFilter || _videoFilter == nullptr) { + if (_videoFilterType != newFilter || _videoFilter == nullptr) + { _videoFilterType = newFilter; _videoFilter.reset(new DefaultVideoFilter(_console)); _scaleFilter.reset(); - switch(_videoFilterType) { - case VideoFilterType::None: break; - case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); break; - default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break; + switch (_videoFilterType) + { + case VideoFilterType::None: break; + case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); + break; + default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); + break; } } } @@ -90,18 +99,22 @@ void VideoDecoder::DecodeFrame(bool forRewind) uint32_t* outputBuffer = _videoFilter->GetOutputBuffer(); FrameInfo frameInfo = _videoFilter->GetFrameInfo(); - + _inputHud->DrawControllers(_videoFilter->GetOverscan(), _frameNumber); _console->GetDebugHud()->Draw(outputBuffer, _videoFilter->GetOverscan(), frameInfo.Width, _frameNumber); - if(_scaleFilter) { - outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetVideoConfig().ScanlineIntensity); + if (_scaleFilter) + { + outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, + _console->GetSettings()->GetVideoConfig().ScanlineIntensity); frameInfo = _scaleFilter->GetFrameInfo(frameInfo); } ScreenSize screenSize = GetScreenSize(true); VideoConfig config = _console->GetSettings()->GetVideoConfig(); - if(_previousScale != config.VideoScale || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) { + if (_previousScale != config.VideoScale || screenSize.Height != _previousScreenSize.Height || screenSize.Width != + _previousScreenSize.Width) + { _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged); } _previousScale = config.VideoScale; @@ -117,11 +130,14 @@ void VideoDecoder::DecodeFrame(bool forRewind) void VideoDecoder::DecodeThread() { //This thread will decode the PPU's output (color ID to RGB, intensify r/g/b and produce a HD version of the frame if needed) - while(!_stopFlag.load()) { + while (!_stopFlag.load()) + { //DecodeFrame returns the final ARGB frame we want to display in the emulator window - while(!_frameChanged) { + while (!_frameChanged) + { _waitForFrame.Wait(); - if(_stopFlag.load()) { + if (_stopFlag.load()) + { return; } } @@ -135,20 +151,24 @@ uint32_t VideoDecoder::GetFrameCount() return _frameCount; } -void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind) +void VideoDecoder::UpdateFrameSync(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, + bool forRewind) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(_frameChanged) { + if (_frameChanged) + { //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay - while(_frameChanged) { + while (_frameChanged) + { //Spin until decode is done } //At this point, we are sure that the decode thread is no longer busy } - + _frameChanged = true; _baseFrameInfo.Width = width; _baseFrameInfo.Height = height; @@ -158,20 +178,23 @@ void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, ui _frameCount++; } -void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) +void VideoDecoder::UpdateFrame(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(_frameChanged) { + if (_frameChanged) + { //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay - while(_frameChanged) { + while (_frameChanged) + { //Spin until decode is done } //At this point, we are sure that the decode thread is no longer busy } - + _baseFrameInfo.Width = width; _baseFrameInfo.Height = height; _frameNumber = frameNumber; @@ -185,12 +208,13 @@ void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16 void VideoDecoder::StartThread() { #ifndef LIBRETRO - if(!_decodeThread) { + if (!_decodeThread) + { _stopFlag = false; _frameChanged = false; _frameCount = 0; _waitForFrame.Reset(); - + _decodeThread.reset(new thread(&VideoDecoder::DecodeThread, this)); } #endif @@ -200,14 +224,16 @@ void VideoDecoder::StopThread() { #ifndef LIBRETRO _stopFlag = true; - if(_decodeThread) { + if (_decodeThread) + { _waitForFrame.Signal(); _decodeThread->join(); _decodeThread.reset(); //Clear whole screen - if(_frameCount > 0) { + if (_frameCount > 0) + { vector outputBuffer(512 * 478, 0); _ppuOutputBuffer = outputBuffer.data(); memset(_ppuOutputBuffer, 0, 512 * 478 * 2); @@ -225,14 +251,16 @@ bool VideoDecoder::IsRunning() void VideoDecoder::TakeScreenshot() { - if(_videoFilter) { + if (_videoFilter) + { _videoFilter->TakeScreenshot(_console->GetRomInfo().RomFile.GetFileName(), _videoFilterType); } } -void VideoDecoder::TakeScreenshot(std::stringstream &stream) +void VideoDecoder::TakeScreenshot(std::stringstream& stream) { - if(_videoFilter) { + if (_videoFilter) + { _videoFilter->TakeScreenshot(_videoFilterType, "", &stream); } } diff --git a/Core/VideoDecoder.h b/Core/VideoDecoder.h index 47f10c0..66359f2 100644 --- a/Core/VideoDecoder.h +++ b/Core/VideoDecoder.h @@ -16,14 +16,14 @@ class VideoDecoder private: shared_ptr _console; - uint16_t *_ppuOutputBuffer = nullptr; + uint16_t* _ppuOutputBuffer = nullptr; uint32_t _frameNumber = 0; unique_ptr _decodeThread; unique_ptr _inputHud; AutoResetEvent _waitForFrame; - + atomic _frameChanged; atomic _stopFlag; uint32_t _frameCount = 0; @@ -48,17 +48,18 @@ public: void DecodeFrame(bool synchronous = false); void TakeScreenshot(); - void TakeScreenshot(std::stringstream &stream); + void TakeScreenshot(std::stringstream& stream); uint32_t GetFrameCount(); FrameInfo GetFrameInfo(); ScreenSize GetScreenSize(bool ignoreScale); - void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind); - void UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); + void UpdateFrameSync(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, + bool forRewind); + void UpdateFrame(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); bool IsRunning(); void StartThread(); void StopThread(); -}; \ No newline at end of file +}; diff --git a/Core/VideoRenderer.cpp b/Core/VideoRenderer.cpp index 3f11646..7ab5d7e 100644 --- a/Core/VideoRenderer.cpp +++ b/Core/VideoRenderer.cpp @@ -12,7 +12,7 @@ VideoRenderer::VideoRenderer(shared_ptr console) { _console = console; - _stopFlag = false; + _stopFlag = false; StartThread(); } @@ -25,7 +25,8 @@ VideoRenderer::~VideoRenderer() void VideoRenderer::StartThread() { #ifndef LIBRETRO - if(!_renderThread) { + if (!_renderThread) + { _stopFlag = false; _waitForRender.Reset(); @@ -38,7 +39,8 @@ void VideoRenderer::StopThread() { #ifndef LIBRETRO _stopFlag = true; - if(_renderThread) { + if (_renderThread) + { _renderThread->join(); _renderThread.reset(); } @@ -47,14 +49,17 @@ void VideoRenderer::StopThread() void VideoRenderer::RenderThread() { - if(_renderer) { + if (_renderer) + { _renderer->Reset(); } - while(!_stopFlag.load()) { + while (!_stopFlag.load()) + { //Wait until a frame is ready, or until 16ms have passed (to allow UI to run at a minimum of 60fps) _waitForRender.Wait(16); - if(_renderer) { + if (_renderer) + { _renderer->Render(); } } @@ -63,25 +68,28 @@ void VideoRenderer::RenderThread() void VideoRenderer::UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { recorder->AddFrame(frameBuffer, width, height, _console->GetFps()); } - if(_renderer) { + if (_renderer) + { _renderer->UpdateFrame(frameBuffer, width, height); _waitForRender.Signal(); } } -void VideoRenderer::RegisterRenderingDevice(IRenderingDevice *renderer) +void VideoRenderer::RegisterRenderingDevice(IRenderingDevice* renderer) { _renderer = renderer; StartThread(); } -void VideoRenderer::UnregisterRenderingDevice(IRenderingDevice *renderer) +void VideoRenderer::UnregisterRenderingDevice(IRenderingDevice* renderer) { - if(_renderer == renderer) { + if (_renderer == renderer) + { StopThread(); _renderer = nullptr; } @@ -92,13 +100,18 @@ void VideoRenderer::StartRecording(string filename, VideoCodec codec, uint32_t c FrameInfo frameInfo = _console->GetVideoDecoder()->GetFrameInfo(); shared_ptr recorder; - if(codec == VideoCodec::GIF) { + if (codec == VideoCodec::GIF) + { recorder.reset(new GifRecorder()); - } else { + } + else + { recorder.reset(new AviRecorder(codec, compressionLevel)); } - if(recorder->StartRecording(filename, frameInfo.Width, frameInfo.Height, 4, _console->GetSettings()->GetAudioConfig().SampleRate, _console->GetFps())) { + if (recorder->StartRecording(filename, frameInfo.Width, frameInfo.Height, 4, + _console->GetSettings()->GetAudioConfig().SampleRate, _console->GetFps())) + { _recorder = recorder; MessageManager::DisplayMessage("VideoRecorder", "VideoRecorderStarted", filename); } @@ -107,7 +120,8 @@ void VideoRenderer::StartRecording(string filename, VideoCodec codec, uint32_t c void VideoRenderer::AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate) { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { recorder->AddSound(soundBuffer, sampleCount, sampleRate); } } @@ -115,7 +129,8 @@ void VideoRenderer::AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount void VideoRenderer::StopRecording() { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { MessageManager::DisplayMessage("VideoRecorder", "VideoRecorderStopped", recorder->GetOutputFile()); } _recorder.reset(); @@ -124,4 +139,4 @@ void VideoRenderer::StopRecording() bool VideoRenderer::IsRecording() { return _recorder != nullptr && _recorder->IsRecording(); -} \ No newline at end of file +} diff --git a/Core/VideoRenderer.h b/Core/VideoRenderer.h index 6ed3504..568cc6b 100644 --- a/Core/VideoRenderer.h +++ b/Core/VideoRenderer.h @@ -30,12 +30,12 @@ public: void StartThread(); void StopThread(); - void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height); - void RegisterRenderingDevice(IRenderingDevice *renderer); - void UnregisterRenderingDevice(IRenderingDevice *renderer); + void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height); + void RegisterRenderingDevice(IRenderingDevice* renderer); + void UnregisterRenderingDevice(IRenderingDevice* renderer); void StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel); void AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate); void StopRecording(); bool IsRecording(); -}; \ No newline at end of file +}; diff --git a/Core/WaveRecorder.cpp b/Core/WaveRecorder.cpp index d628e7b..4004e0f 100644 --- a/Core/WaveRecorder.cpp +++ b/Core/WaveRecorder.cpp @@ -9,8 +9,9 @@ WaveRecorder::WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo _streamSize = 0; _sampleRate = sampleRate; _isStereo = isStereo; - - if(_stream) { + + if (_stream) + { WriteHeader(); MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStarted", _outputFile); } @@ -52,13 +53,16 @@ void WaveRecorder::WriteHeader() _stream.write((char*)&size, sizeof(size)); } -bool WaveRecorder::WriteSamples(int16_t * samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +bool WaveRecorder::WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) { - if(_sampleRate != sampleRate || _isStereo != isStereo) { + if (_sampleRate != sampleRate || _isStereo != isStereo) + { //Format changed, stop recording CloseFile(); return false; - } else { + } + else + { uint32_t sampleBytes = sampleCount * (isStereo ? 4 : 2); _stream.write((char*)samples, sampleBytes); _streamSize += sampleBytes; @@ -78,7 +82,8 @@ void WaveRecorder::UpdateSizeValues() void WaveRecorder::CloseFile() { - if(_stream && _stream.is_open()) { + if (_stream && _stream.is_open()) + { UpdateSizeValues(); _stream.close(); diff --git a/Core/WaveRecorder.h b/Core/WaveRecorder.h index 1cb3dab..7b51f99 100644 --- a/Core/WaveRecorder.h +++ b/Core/WaveRecorder.h @@ -18,4 +18,4 @@ public: ~WaveRecorder(); bool WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo); -}; \ No newline at end of file +}; diff --git a/Core/blargg_common.h b/Core/blargg_common.h index 75edff3..d73c065 100644 --- a/Core/blargg_common.h +++ b/Core/blargg_common.h @@ -18,62 +18,75 @@ // BLARGG_RESTRICT: equivalent to restrict, where supported #if defined (__GNUC__) || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict +#define BLARGG_RESTRICT __restrict #else #define BLARGG_RESTRICT #endif // STATIC_CAST(T,expr): Used in place of static_cast (expr) #ifndef STATIC_CAST - #define STATIC_CAST(T,expr) ((T) (expr)) +#define STATIC_CAST(T,expr) ((T) (expr)) #endif // blargg_err_t (0 on success, otherwise error string) #ifndef blargg_err_t - typedef const char* blargg_err_t; +typedef const char* blargg_err_t; #endif // blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { +template +class blargg_vector +{ T* begin_; size_t size_; public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } + blargg_vector() : begin_(0), size_(0) + { + } + + ~blargg_vector() { free(begin_); } size_t size() const { return size_; } T* begin() const { return begin_; } T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) + + blargg_err_t resize(size_t n) { // TODO: blargg_common.cpp to hold this as an outline function, ugh - void* p = realloc( begin_, n * sizeof (T) ); - if ( p ) - begin_ = (T*) p; - else if ( n > size_ ) // realloc failure only a problem if expanding + void* p = realloc(begin_, n * sizeof(T)); + if (p) + begin_ = (T*)p; + else if (n > size_) // realloc failure only a problem if expanding return "Out of memory"; size_ = n; return 0; } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const + + void clear() { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; + void* p = begin_; + begin_ = 0; + size_ = 0; + free(p); + } + + T& operator [](size_t n) const + { + assert(n <= size_); // <= to allow past-the-end value + return begin_[n]; } }; #ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || defined (__GNUC__) - #define BLARGG_THROWS( spec ) throw spec - #else +// throw spec mandatory in ISO C++ if operator new can return NULL +#if __cplusplus >= 199711 || defined (__GNUC__) +#define BLARGG_THROWS( spec ) throw spec +#else #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ +#endif +#define BLARGG_DISABLE_NOTHROW \ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new +#define BLARGG_NEW new #else #include #define BLARGG_NEW new (std::nothrow) @@ -85,34 +98,34 @@ public: // BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. #ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ +#ifdef _MSC_VER +// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified +#define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else +#else // Some other compilers fail when declaring same function multiple times in class, // so differentiate them by line #define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif +#endif #endif // BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, // compiler is assumed to support bool. If undefined, availability is determined. #ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) +#if defined (__MWERKS__) +#if !__option(bool) #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 +#endif +#elif defined (_MSC_VER) +#if _MSC_VER < 1100 #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 +#endif +#elif defined (__GNUC__) +// supports bool +#elif __cplusplus < 199711 #define BLARGG_COMPILER_HAS_BOOL 0 - #endif +#endif #endif #if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL // If you get errors here, modify your blargg_config.h file @@ -124,13 +137,13 @@ public: // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; +typedef long blargg_long; #else typedef int blargg_long; #endif #if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; +typedef unsigned long blargg_ulong; #else typedef unsigned blargg_ulong; #endif @@ -148,38 +161,38 @@ public: #define BOOST #else - struct BOOST - { - #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F - typedef signed char int8_t; - typedef unsigned char uint8_t; - #else +struct BOOST +{ +#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; +#else // No suitable 8-bit type available typedef struct see_blargg_common_h int8_t; typedef struct see_blargg_common_h uint8_t; - #endif - - #if USHRT_MAX == 0xFFFF - typedef short int16_t; - typedef unsigned short uint16_t; - #else +#endif + +#if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; +#else // No suitable 16-bit type available typedef struct see_blargg_common_h int16_t; typedef struct see_blargg_common_h uint16_t; - #endif - - #if ULONG_MAX == 0xFFFFFFFF - typedef long int32_t; - typedef unsigned long uint32_t; - #elif UINT_MAX == 0xFFFFFFFF +#endif + +#if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; +#elif UINT_MAX == 0xFFFFFFFF typedef int int32_t; typedef unsigned int uint32_t; - #else +#else // No suitable 32-bit type available typedef struct see_blargg_common_h int32_t; typedef struct see_blargg_common_h uint32_t; - #endif - }; +#endif +}; #endif #endif diff --git a/Core/blargg_endian.h b/Core/blargg_endian.h index f2daca6..79f3745 100644 --- a/Core/blargg_endian.h +++ b/Core/blargg_endian.h @@ -24,11 +24,11 @@ #ifdef __GLIBC__ // GCC handles this for us #include - #if __BYTE_ORDER == __LITTLE_ENDIAN +#if __BYTE_ORDER == __LITTLE_ENDIAN #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN #define BLARGG_BIG_ENDIAN 1 - #endif +#endif #else #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ @@ -41,8 +41,8 @@ (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) #define BLARGG_BIG_ENDIAN 1 #elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 +// No endian specified; assume little-endian, since it's most common +#define BLARGG_LITTLE_ENDIAN 1 #endif #endif #endif @@ -54,132 +54,148 @@ inline void blargg_verify_byte_order() { - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN +#ifndef NDEBUG +#if BLARGG_BIG_ENDIAN volatile int i = 1; assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif +#elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert(*(volatile char*) &i != 0); +#endif +#endif } -inline unsigned get_le16( void const* p ) +inline unsigned get_le16(void const* p) { - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; + return (unsigned)((unsigned char const*)p)[1] << 8 | + (unsigned)((unsigned char const*)p)[0]; } -inline unsigned get_be16( void const* p ) +inline unsigned get_be16(void const* p) { - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; + return (unsigned)((unsigned char const*)p)[0] << 8 | + (unsigned)((unsigned char const*)p)[1]; } -inline blargg_ulong get_le32( void const* p ) +inline blargg_ulong get_le32(void const* p) { - return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | - (blargg_ulong) ((unsigned char const*) p) [2] << 16 | - (blargg_ulong) ((unsigned char const*) p) [1] << 8 | - (blargg_ulong) ((unsigned char const*) p) [0]; + return (blargg_ulong)((unsigned char const*)p)[3] << 24 | + (blargg_ulong)((unsigned char const*)p)[2] << 16 | + (blargg_ulong)((unsigned char const*)p)[1] << 8 | + (blargg_ulong)((unsigned char const*)p)[0]; } -inline blargg_ulong get_be32( void const* p ) +inline blargg_ulong get_be32(void const* p) { - return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | - (blargg_ulong) ((unsigned char const*) p) [1] << 16 | - (blargg_ulong) ((unsigned char const*) p) [2] << 8 | - (blargg_ulong) ((unsigned char const*) p) [3]; + return (blargg_ulong)((unsigned char const*)p)[0] << 24 | + (blargg_ulong)((unsigned char const*)p)[1] << 16 | + (blargg_ulong)((unsigned char const*)p)[2] << 8 | + (blargg_ulong)((unsigned char const*)p)[3]; } -inline void set_le16( void* p, unsigned n ) +inline void set_le16(void* p, unsigned n) { - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*)p)[1] = (unsigned char)(n >> 8); + ((unsigned char*)p)[0] = (unsigned char)n; } -inline void set_be16( void* p, unsigned n ) +inline void set_be16(void* p, unsigned n) { - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; + ((unsigned char*)p)[0] = (unsigned char)(n >> 8); + ((unsigned char*)p)[1] = (unsigned char)n; } -inline void set_le32( void* p, blargg_ulong n ) +inline void set_le32(void* p, blargg_ulong n) { - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); + ((unsigned char*)p)[0] = (unsigned char)n; + ((unsigned char*)p)[1] = (unsigned char)(n >> 8); + ((unsigned char*)p)[2] = (unsigned char)(n >> 16); + ((unsigned char*)p)[3] = (unsigned char)(n >> 24); } -inline void set_be32( void* p, blargg_ulong n ) +inline void set_be32(void* p, blargg_ulong n) { - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); + ((unsigned char*)p)[3] = (unsigned char)n; + ((unsigned char*)p)[2] = (unsigned char)(n >> 8); + ((unsigned char*)p)[1] = (unsigned char)(n >> 16); + ((unsigned char*)p)[0] = (unsigned char)(n >> 24); } #if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN +// Optimized implementation if byte order is known +#if BLARGG_LITTLE_ENDIAN #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN +#elif BLARGG_BIG_ENDIAN #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) +#if BLARGG_CPU_POWERPC +// PowerPC has special byte-reversed instructions +#if defined (__MWERKS__) #define GET_LE16( addr ) (__lhbrx( addr, 0 )) #define GET_LE32( addr ) (__lwbrx( addr, 0 )) #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) +#elif defined (__GNUC__) #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #endif - #endif - #endif +#endif +#endif +#endif #endif #ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) +#define GET_LE16( addr ) get_le16( addr ) +#define SET_LE16( addr, data ) set_le16( addr, data ) #endif #ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) +#define GET_LE32( addr ) get_le32( addr ) +#define SET_LE32( addr, data ) set_le32( addr, data ) #endif #ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) +#define GET_BE16( addr ) get_be16( addr ) +#define SET_BE16( addr, data ) set_be16( addr, data ) #endif #ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) +#define GET_BE32( addr ) get_be32( addr ) +#define SET_BE32( addr, data ) set_be32( addr, data ) #endif // auto-selecting versions -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } -inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } -inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } +inline void set_le(BOOST::uint16_t* p, unsigned n) +{ + SET_LE16(p, n); +} + +inline void set_le(BOOST::uint32_t* p, blargg_ulong n) +{ + SET_LE32(p, n); +} + +inline void set_be(BOOST::uint16_t* p, unsigned n) +{ + SET_BE16(p, n); +} + +inline void set_be(BOOST::uint32_t* p, blargg_ulong n) +{ + SET_BE32(p, n); +} + +inline unsigned get_le(BOOST::uint16_t* p) { return GET_LE16(p); } +inline blargg_ulong get_le(BOOST::uint32_t* p) { return GET_LE32(p); } +inline unsigned get_be(BOOST::uint16_t* p) { return GET_BE16(p); } +inline blargg_ulong get_be(BOOST::uint32_t* p) { return GET_BE32(p); } #endif diff --git a/Core/blargg_source.h b/Core/blargg_source.h index 5e45c4f..2b845f8 100644 --- a/Core/blargg_source.h +++ b/Core/blargg_source.h @@ -22,7 +22,9 @@ all other #include lines. */ // Like printf() except output goes to debug log file. Might be defined to do // nothing (not even evaluate its arguments). // void dprintf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } +static inline void blargg_dprintf_(const char*, ...) +{ +} #undef dprintf #define dprintf (1) ? (void) 0 : blargg_dprintf_ @@ -51,12 +53,12 @@ static inline void blargg_dprintf_( const char*, ... ) { } static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ static inline type max( type x, type y ) { if ( y < x ) return x; return y; } -DEF_MIN_MAX( int ) -DEF_MIN_MAX( unsigned ) -DEF_MIN_MAX( long ) -DEF_MIN_MAX( unsigned long ) -DEF_MIN_MAX( float ) -DEF_MIN_MAX( double ) +DEF_MIN_MAX(int) +DEF_MIN_MAX(unsigned) +DEF_MIN_MAX(long) +DEF_MIN_MAX(unsigned long) +DEF_MIN_MAX(float) +DEF_MIN_MAX(double) #undef DEF_MIN_MAX diff --git a/Core/stdafx.h b/Core/stdafx.h index 82bd244..b2f4678 100644 --- a/Core/stdafx.h +++ b/Core/stdafx.h @@ -25,13 +25,13 @@ #include "../Utilities/UTF8Util.h" #ifndef __MINGW32__ - #ifdef __clang__ +#ifdef __clang__ #define __forceinline __attribute__((always_inline)) inline - #else - #ifdef __GNUC__ +#else +#ifdef __GNUC__ #define __forceinline __attribute__((always_inline)) inline - #endif - #endif +#endif +#endif #endif using std::vector;