Merge branch 'reformat_code'

This commit is contained in:
Vladimir Kononovich 2020-12-19 23:33:29 +03:00
commit daf3b57e89
573 changed files with 82336 additions and 65195 deletions

View file

@ -17,22 +17,28 @@ void AluMulDiv::Run(bool isRead)
{ {
uint64_t cpuCycle = _cpu->GetCycleCount(); 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 //Run 1 cycle less for read operations, since they occur earlier within the CPU cycle, compared to a write
cpuCycle--; cpuCycle--;
} }
if(_multCounter != 0 || _divCounter != 0) { if (_multCounter != 0 || _divCounter != 0)
{
uint64_t cyclesToRun = cpuCycle - _prevCpuCycle; uint64_t cyclesToRun = cpuCycle - _prevCpuCycle;
while(cyclesToRun--) { while (cyclesToRun--)
if(!_multCounter && !_divCounter) { {
if (!_multCounter && !_divCounter)
{
break; break;
} }
if(_multCounter > 0) { if (_multCounter > 0)
{
_multCounter--; _multCounter--;
if(_state.DivResult & 0x01) { if (_state.DivResult & 0x01)
{
_state.MultOrRemainderResult += _shift; _state.MultOrRemainderResult += _shift;
} }
@ -40,19 +46,21 @@ void AluMulDiv::Run(bool isRead)
_state.DivResult >>= 1; _state.DivResult >>= 1;
} }
if(_divCounter > 0) { if (_divCounter > 0)
{
_divCounter--; _divCounter--;
_shift >>= 1; _shift >>= 1;
_state.DivResult <<= 1; _state.DivResult <<= 1;
if(_state.MultOrRemainderResult >= _shift) { if (_state.MultOrRemainderResult >= _shift)
{
_state.MultOrRemainderResult -= _shift; _state.MultOrRemainderResult -= _shift;
_state.DivResult |= 1; _state.DivResult |= 1;
} }
} }
} }
} }
_prevCpuCycle = cpuCycle; _prevCpuCycle = cpuCycle;
} }
@ -60,12 +68,13 @@ uint8_t AluMulDiv::Read(uint16_t addr)
{ {
Run(true); Run(true);
switch(addr) { switch (addr)
case 0x4214: return (uint8_t)_state.DivResult; {
case 0x4215: return (uint8_t)(_state.DivResult >> 8); case 0x4214: return (uint8_t)_state.DivResult;
case 0x4215: return (uint8_t)(_state.DivResult >> 8);
case 0x4216: return (uint8_t)_state.MultOrRemainderResult; case 0x4216: return (uint8_t)_state.MultOrRemainderResult;
case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8); case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8);
} }
throw std::runtime_error("ALU: invalid address"); throw std::runtime_error("ALU: invalid address");
@ -75,33 +84,39 @@ void AluMulDiv::Write(uint16_t addr, uint8_t value)
{ {
Run(false); Run(false);
switch(addr) { switch (addr)
case 0x4202: _state.MultOperand1 = value; break; {
case 0x4203: case 0x4202: _state.MultOperand1 = value;
_state.MultOrRemainderResult = 0; break;
if(!_divCounter && !_multCounter) { case 0x4203:
_multCounter = 8; _state.MultOrRemainderResult = 0;
if (!_divCounter && !_multCounter)
{
_multCounter = 8;
_state.MultOperand2 = value; _state.MultOperand2 = value;
_state.DivResult = (value << 8) | _state.MultOperand1; _state.DivResult = (value << 8) | _state.MultOperand1;
_shift = value; _shift = value;
} }
break; break;
case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value; break; case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value;
case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8); break; break;
case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8);
case 0x4206: break;
_state.MultOrRemainderResult = _state.Dividend;
if(!_divCounter && !_multCounter) { case 0x4206:
_divCounter = 16; _state.MultOrRemainderResult = _state.Dividend;
_state.Divisor = value;
_shift = (value << 16);
}
break;
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; return _state;
} }
void AluMulDiv::Serialize(Serializer &s) void AluMulDiv::Serialize(Serializer& s)
{ {
s.Stream( 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 _divCounter, _multCounter, _shift, _prevCpuCycle
); );
} }

View file

@ -8,7 +8,7 @@ class Cpu;
class AluMulDiv final : public ISerializable class AluMulDiv final : public ISerializable
{ {
private: private:
Cpu *_cpu; Cpu* _cpu;
uint64_t _prevCpuCycle = 0; uint64_t _prevCpuCycle = 0;
@ -17,10 +17,10 @@ private:
uint32_t _shift = 0; uint32_t _shift = 0;
uint8_t _multCounter = 0; uint8_t _multCounter = 0;
uint8_t _divCounter = 0; uint8_t _divCounter = 0;
public: public:
void Initialize(Cpu* cpu); void Initialize(Cpu* cpu);
void Run(bool isRead); void Run(bool isRead);
uint8_t Read(uint16_t addr); uint8_t Read(uint16_t addr);
@ -28,5 +28,5 @@ public:
AluState GetState(); AluState GetState();
void Serialize(Serializer &s) override; void Serialize(Serializer& s) override;
}; };

View file

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

View file

@ -28,9 +28,13 @@ private:
bool _needSecondPass; bool _needSecondPass;
shared_ptr<LabelManager> _labelManager; shared_ptr<LabelManager> _labelManager;
void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint32_t>& labels, bool firstPass, std::unordered_map<string, uint32_t>& currentPassLabels); void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output,
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass); std::unordered_map<string, uint32_t>& labels, bool firstPass,
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass); std::unordered_map<string, uint32_t>& currentPassLabels);
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass);
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels,
bool firstPass);
void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output, bool firstPass); void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output, bool firstPass);
bool IsOpModeAvailable(string& opCode, AddrMode mode); bool IsOpModeAvailable(string& opCode, AddrMode mode);
@ -40,4 +44,4 @@ public:
virtual ~Assembler(); virtual ~Assembler();
uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode);
}; };

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@ enum class ConsoleRegion;
class BaseCartridge : public ISerializable class BaseCartridge : public ISerializable
{ {
private: private:
Console *_console; Console* _console;
vector<unique_ptr<IMemoryHandler>> _prgRomHandlers; vector<unique_ptr<IMemoryHandler>> _prgRomHandlers;
vector<unique_ptr<IMemoryHandler>> _saveRamHandlers; vector<unique_ptr<IMemoryHandler>> _saveRamHandlers;
@ -32,12 +32,12 @@ private:
bool _needCoprocSync = false; bool _needCoprocSync = false;
unique_ptr<BaseCoprocessor> _coprocessor; unique_ptr<BaseCoprocessor> _coprocessor;
NecDsp *_necDsp = nullptr; NecDsp* _necDsp = nullptr;
Sa1 *_sa1 = nullptr; Sa1* _sa1 = nullptr;
Gsu *_gsu = nullptr; Gsu* _gsu = nullptr;
Cx4 *_cx4 = nullptr; Cx4* _cx4 = nullptr;
SuperGameboy *_sgb = nullptr; SuperGameboy* _sgb = nullptr;
BsxCart* _bsx = nullptr; BsxCart* _bsx = nullptr;
unique_ptr<BsxMemoryPack> _bsxMemPack; unique_ptr<BsxMemoryPack> _bsxMemPack;
unique_ptr<Gameboy> _gameboy; unique_ptr<Gameboy> _gameboy;
@ -51,11 +51,11 @@ private:
uint8_t* _prgRom = nullptr; uint8_t* _prgRom = nullptr;
uint8_t* _saveRam = nullptr; uint8_t* _saveRam = nullptr;
uint32_t _prgRomSize = 0; uint32_t _prgRomSize = 0;
uint32_t _saveRamSize = 0; uint32_t _saveRamSize = 0;
uint32_t _coprocessorRamSize = 0; uint32_t _coprocessorRamSize = 0;
shared_ptr<SpcFileData> _spcData; shared_ptr<SpcFileData> _spcData;
vector<uint8_t> _embeddedFirmware; vector<uint8_t> _embeddedFirmware;
@ -71,7 +71,7 @@ private:
bool MapSpecificCarts(MemoryMappings& mm); bool MapSpecificCarts(MemoryMappings& mm);
void MapBsxMemoryPack(MemoryMappings& mm); void MapBsxMemoryPack(MemoryMappings& mm);
void ApplyConfigOverrides(); void ApplyConfigOverrides();
void LoadRom(); void LoadRom();
void LoadSpc(); void LoadSpc();
bool LoadGameboy(VirtualFile& romFile, bool sgbEnabled); bool LoadGameboy(VirtualFile& romFile, bool sgbEnabled);
@ -85,13 +85,13 @@ private:
public: public:
virtual ~BaseCartridge(); virtual ~BaseCartridge();
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile); static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile);
void Reset(); void Reset();
void SaveBattery(); void SaveBattery();
void Init(MemoryMappings &mm); void Init(MemoryMappings& mm);
RomInfo GetRomInfo(); RomInfo GetRomInfo();
vector<uint8_t> GetOriginalPrgRom(); vector<uint8_t> GetOriginalPrgRom();
@ -100,7 +100,7 @@ public:
string GetSha1Hash(); string GetSha1Hash();
CartFlags::CartFlags GetCartFlags(); CartFlags::CartFlags GetCartFlags();
void RegisterHandlers(MemoryMappings &mm); void RegisterHandlers(MemoryMappings& mm);
uint8_t* DebugGetPrgRom() { return _prgRom; } uint8_t* DebugGetPrgRom() { return _prgRom; }
uint8_t* DebugGetSaveRam() { return _saveRam; } uint8_t* DebugGetSaveRam() { return _saveRam; }
@ -117,10 +117,11 @@ public:
Gameboy* GetGameboy(); Gameboy* GetGameboy();
void RunCoprocessors(); void RunCoprocessors();
__forceinline void SyncCoprocessors() __forceinline void SyncCoprocessors()
{ {
if(_needCoprocSync) { if (_needCoprocSync)
{
_coprocessor->Run(); _coprocessor->Run();
} }
} }
@ -132,5 +133,5 @@ public:
SpcFileData* GetSpcData(); SpcFileData* GetSpcData();
void Serialize(Serializer &s) override; void Serialize(Serializer& s) override;
}; };

View file

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

View file

@ -20,8 +20,10 @@ protected:
uint8_t _port; uint8_t _port;
SimpleLock _stateLock; SimpleLock _stateLock;
virtual void RefreshStateBuffer() { } virtual void RefreshStateBuffer()
{
}
void EnsureCapacity(int32_t minBitCount); void EnsureCapacity(int32_t minBitCount);
uint32_t GetByteIndex(uint8_t bit); uint32_t GetByteIndex(uint8_t bit);
virtual bool HasCoordinates(); virtual bool HasCoordinates();
@ -41,9 +43,9 @@ protected:
void SetMovement(MouseMovement mov); void SetMovement(MouseMovement mov);
MouseMovement GetMovement(); MouseMovement GetMovement();
virtual void InternalSetStateFromInput(); virtual void InternalSetStateFromInput();
public: public:
static constexpr uint8_t ExpDevicePort = 4; static constexpr uint8_t ExpDevicePort = 4;
static constexpr uint8_t ConsoleInputPort = 5; static constexpr uint8_t ConsoleInputPort = 5;
@ -58,27 +60,31 @@ public:
bool IsPressed(uint8_t bit); bool IsPressed(uint8_t bit);
MousePosition GetCoordinates(); MousePosition GetCoordinates();
void ClearState(); void ClearState();
void SetBit(uint8_t bit); void SetBit(uint8_t bit);
void ClearBit(uint8_t bit); void ClearBit(uint8_t bit);
void InvertBit(uint8_t bit); void InvertBit(uint8_t bit);
void SetBitValue(uint8_t bit, bool set); void SetBitValue(uint8_t bit, bool set);
void SetTextState(string state); void SetTextState(string state);
string GetTextState(); string GetTextState();
void SetStateFromInput(); void SetStateFromInput();
virtual void OnAfterSetState() { }
virtual void OnAfterSetState()
{
}
void SetRawState(ControlDeviceState state); void SetRawState(ControlDeviceState state);
ControlDeviceState GetRawState(); ControlDeviceState GetRawState();
virtual ControllerType GetControllerType() = 0; virtual ControllerType GetControllerType() = 0;
virtual uint8_t ReadRam(uint16_t addr) = 0; virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0; virtual void WriteRam(uint16_t addr, uint8_t value) = 0;
void static SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2, uint8_t button2);
void Serialize(Serializer &s) override; void static SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2,
uint8_t button2);
void Serialize(Serializer& s) override;
}; };

View file

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

View file

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

View file

@ -17,7 +17,7 @@ private:
uint32_t _currentRenderedFPS = 0; uint32_t _currentRenderedFPS = 0;
void RemoveOldToasts(); 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 float MeasureString(std::wstring text) = 0;
virtual bool ContainsCharacter(wchar_t character) = 0; virtual bool ContainsCharacter(wchar_t character) = 0;
@ -26,19 +26,20 @@ protected:
uint32_t _screenWidth = 0; uint32_t _screenWidth = 0;
uint32_t _screenHeight = 0; uint32_t _screenHeight = 0;
uint32_t _renderedFrameCount = 0; uint32_t _renderedFrameCount = 0;
BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager); BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager);
virtual ~BaseRenderer(); virtual ~BaseRenderer();
bool IsMessageShown(); bool IsMessageShown();
void DisplayMessage(string title, string message); void DisplayMessage(string title, string message);
void DrawToasts(); void DrawToasts();
void DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight); void DrawToast(shared_ptr<ToastInfo> toast, int& lastHeight);
void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255); void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255);
virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255) = 0; virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255,
uint8_t opacity = 255) = 0;
void ShowFpsCounter(int lineNumber); void ShowFpsCounter(int lineNumber);
void ShowLagCounter(int lineNumber); void ShowLagCounter(int lineNumber);

View file

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

View file

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

View file

@ -20,7 +20,7 @@ protected:
shared_ptr<Console> _console; shared_ptr<Console> _console;
FrameInfo _baseFrameInfo; FrameInfo _baseFrameInfo;
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0; virtual void ApplyFilter(uint16_t* ppuOutputBuffer) = 0;
virtual void OnBeforeApplyFilter(); virtual void OnBeforeApplyFilter();
bool IsOddFrame(); bool IsOddFrame();
uint32_t GetBufferSize(); uint32_t GetBufferSize();
@ -31,12 +31,12 @@ public:
virtual ~BaseVideoFilter(); virtual ~BaseVideoFilter();
uint32_t* GetOutputBuffer(); 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(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(); virtual OverscanDimensions GetOverscan();
void SetBaseFrameInfo(FrameInfo frameInfo); void SetBaseFrameInfo(FrameInfo frameInfo);
virtual FrameInfo GetFrameInfo(); virtual FrameInfo GetFrameInfo();
}; };

View file

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

View file

@ -30,9 +30,9 @@ public:
void SetBatteryProvider(shared_ptr<IBatteryProvider> provider); void SetBatteryProvider(shared_ptr<IBatteryProvider> provider);
void SetBatteryRecorder(shared_ptr<IBatteryRecorder> recorder); void SetBatteryRecorder(shared_ptr<IBatteryRecorder> recorder);
void SaveBattery(string extension, uint8_t* data, uint32_t length); void SaveBattery(string extension, uint8_t* data, uint32_t length);
vector<uint8_t> LoadBattery(string extension); vector<uint8_t> LoadBattery(string extension);
void LoadBattery(string extension, uint8_t* data, uint32_t length); void LoadBattery(string extension, uint8_t* data, uint32_t length);
}; };

View file

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

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "stdafx.h" #include "stdafx.h"
enum class CpuType : uint8_t; enum class CpuType : uint8_t;
enum class SnesMemoryType; enum class SnesMemoryType;
struct AddressInfo; struct AddressInfo;
enum class BreakpointType; enum class BreakpointType;
@ -11,7 +11,7 @@ enum class BreakpointCategory;
class Breakpoint class Breakpoint
{ {
public: public:
bool Matches(uint32_t memoryAddr, AddressInfo &info); bool Matches(uint32_t memoryAddr, AddressInfo& info);
bool HasBreakpointType(BreakpointType bpType); bool HasBreakpointType(BreakpointType bpType);
string GetCondition(); string GetCondition();
bool HasCondition(); bool HasCondition();
@ -28,4 +28,4 @@ public:
bool enabled; bool enabled;
bool markEvent; bool markEvent;
char condition[1000]; char condition[1000];
}; };

View file

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

View file

@ -15,10 +15,10 @@ class BreakpointManager
private: private:
static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec
Debugger *_debugger; Debugger* _debugger;
CpuType _cpuType; CpuType _cpuType;
IEventManager *_eventManager; IEventManager* _eventManager;
unordered_map<int, Breakpoint> _breakpoints[BreakpointTypeCount]; unordered_map<int, Breakpoint> _breakpoints[BreakpointTypeCount];
unordered_map<int, ExpressionData> _rpnList[BreakpointTypeCount]; unordered_map<int, ExpressionData> _rpnList[BreakpointTypeCount];
bool _hasBreakpoint; bool _hasBreakpoint;
@ -27,20 +27,21 @@ private:
unique_ptr<ExpressionEvaluator> _bpExpEval; unique_ptr<ExpressionEvaluator> _bpExpEval;
BreakpointType GetBreakpointType(MemoryOperationType type); BreakpointType GetBreakpointType(MemoryOperationType type);
int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address);
public: 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 SetBreakpoints(Breakpoint breakpoints[], uint32_t count);
void GetBreakpoints(Breakpoint* breakpoints, int& execs, int& reads, int& writes); 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 -1;
} }
return InternalCheckBreakpoint(operationInfo, address); return InternalCheckBreakpoint(operationInfo, address);
} }

View file

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

View file

@ -22,7 +22,7 @@ private:
uint8_t _regs[0x10] = {}; uint8_t _regs[0x10] = {};
uint8_t _dirtyRegs[0x10] = {}; uint8_t _dirtyRegs[0x10] = {};
bool _dirty = false; bool _dirty = false;
void UpdateMemoryMappings(); void UpdateMemoryMappings();
public: public:
@ -41,4 +41,4 @@ public:
uint8_t* DebugGetPsRam(); uint8_t* DebugGetPsRam();
uint32_t DebugGetPsRamSize(); uint32_t DebugGetPsRamSize();
}; };

View file

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

View file

@ -35,11 +35,11 @@ public:
void ProcessCommand(uint8_t value, uint32_t page); void ProcessCommand(uint8_t value, uint32_t page);
void Reset(); void Reset();
vector<unique_ptr<IMemoryHandler>>& GetMemoryHandlers(); vector<unique_ptr<IMemoryHandler>>& GetMemoryHandlers();
uint8_t* DebugGetMemoryPack(); uint8_t* DebugGetMemoryPack();
uint32_t DebugGetMemoryPackSize(); uint32_t DebugGetMemoryPackSize();
class BsxMemoryPackHandler : public RamHandler class BsxMemoryPackHandler : public RamHandler
{ {
BsxMemoryPack* _memPack; BsxMemoryPack* _memPack;

View file

@ -21,9 +21,12 @@ void BsxSatellaview::Reset()
_extOutput = 0xFF; _extOutput = 0xFF;
time_t resetDate; time_t resetDate;
if(_customDate >= 0) { if (_customDate >= 0)
{
resetDate = (time_t)_customDate; resetDate = (time_t)_customDate;
} else { }
else
{
//Use the current date/time as the BS-X date/time //Use the current date/time as the BS-X date/time
time(&resetDate); time(&resetDate);
} }
@ -35,35 +38,37 @@ void BsxSatellaview::Reset()
uint8_t BsxSatellaview::Read(uint32_t addr) uint8_t BsxSatellaview::Read(uint32_t addr)
{ {
addr &= 0xFFFF; addr &= 0xFFFF;
if(addr >= 0x2188 && addr <= 0x219F) { if (addr >= 0x2188 && addr <= 0x219F)
{
//Handle BS-X $2188-219F registers //Handle BS-X $2188-219F registers
ProcessClocks(); ProcessClocks();
switch(addr) { switch (addr)
case 0x2188: return _stream[0].GetChannel() & 0xFF; {
case 0x2189: return (_stream[0].GetChannel()) >> 8; case 0x2188: return _stream[0].GetChannel() & 0xFF;
case 0x218A: return _stream[0].GetPrefixCount(); case 0x2189: return (_stream[0].GetChannel()) >> 8;
case 0x218B: return _stream[0].GetPrefix(); case 0x218A: return _stream[0].GetPrefixCount();
case 0x218C: return _stream[0].GetData(); case 0x218B: return _stream[0].GetPrefix();
case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0); 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);
case 0x2194: return _streamReg; //LED and Stream register case 0x218E: return _stream[1].GetChannel() & 0xFF;
case 0x2195: return 0; //Unknown case 0x218F: return (_stream[1].GetChannel()) >> 8;
case 0x2196: return 0x10; //Satellaview status case 0x2190: return _stream[1].GetPrefixCount();
case 0x2197: return _extOutput; //Soundlink / EXT output case 0x2191: return _stream[1].GetPrefix();
case 0x2198: return 0x80; //Serial IO (Serial number) case 0x2192: return _stream[1].GetData();
case 0x2199: return 0x01; //Serial IO (???) case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0);
case 0x219A: return 0x10; //Unknown
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 //Use regular B-bus handler for everything else
return _bBusHandler->Read(addr); return _bBusHandler->Read(addr);
} }
@ -71,25 +76,39 @@ uint8_t BsxSatellaview::Read(uint32_t addr)
void BsxSatellaview::Write(uint32_t addr, uint8_t value) void BsxSatellaview::Write(uint32_t addr, uint8_t value)
{ {
addr &= 0xFFFF; addr &= 0xFFFF;
if(addr >= 0x2188 && addr <= 0x219F) { if (addr >= 0x2188 && addr <= 0x219F)
{
//Handle BS-X register writes //Handle BS-X register writes
ProcessClocks(); ProcessClocks();
switch(addr) { switch (addr)
case 0x2188: _stream[0].SetChannelLow(value); break; {
case 0x2189: _stream[0].SetChannelHigh(value); break; case 0x2188: _stream[0].SetChannelLow(value);
case 0x218B: _stream[0].SetPrefixLatch(value); break; break;
case 0x218C: _stream[0].SetDataLatch(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 0x218E: _stream[1].SetChannelLow(value);
case 0x218F: _stream[1].SetChannelHigh(value); break; break;
case 0x2191: _stream[1].SetPrefixLatch(value); break; case 0x218F: _stream[1].SetChannelHigh(value);
case 0x2192: _stream[1].SetDataLatch(value); break; break;
case 0x2191: _stream[1].SetPrefixLatch(value);
break;
case 0x2192: _stream[1].SetDataLatch(value);
break;
case 0x2194: _streamReg = value; break; case 0x2194: _streamReg = value;
case 0x2197: _extOutput = value; break; break;
case 0x2197: _extOutput = value;
break;
} }
} else { }
else
{
//Regular B-bus handler //Regular B-bus handler
_bBusHandler->Write(addr, value); _bBusHandler->Write(addr, value);
} }
@ -97,13 +116,16 @@ void BsxSatellaview::Write(uint32_t addr, uint8_t value)
void BsxSatellaview::ProcessClocks() 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 gap = _memoryManager->GetMasterClock() - _prevMasterClock;
uint64_t clocksPerFrame = _console->GetMasterClockRate() / 1000; //1000 frames/sec (224kbits/sec) 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(); bool needUpdate = _stream[0].FillQueues() || _stream[1].FillQueues();
if(!needUpdate) { if (!needUpdate)
{
gap = 0; gap = 0;
break; break;
} }
@ -111,7 +133,9 @@ void BsxSatellaview::ProcessClocks()
} }
_prevMasterClock = _memoryManager->GetMasterClock() - gap; _prevMasterClock = _memoryManager->GetMasterClock() - gap;
} else { }
else
{
_prevMasterClock = _memoryManager->GetMasterClock(); _prevMasterClock = _memoryManager->GetMasterClock();
} }
} }
@ -128,7 +152,7 @@ void BsxSatellaview::PeekBlock(uint32_t addr, uint8_t* output)
AddressInfo BsxSatellaview::GetAbsoluteAddress(uint32_t address) AddressInfo BsxSatellaview::GetAbsoluteAddress(uint32_t address)
{ {
return { -1, SnesMemoryType::Register }; return {-1, SnesMemoryType::Register};
} }
void BsxSatellaview::Serialize(Serializer& s) void BsxSatellaview::Serialize(Serializer& s)

View file

@ -24,7 +24,7 @@ private:
void ProcessClocks(); void ProcessClocks();
public: public:
BsxSatellaview(Console* console, IMemoryHandler *bBusHandler); BsxSatellaview(Console* console, IMemoryHandler* bBusHandler);
void Reset(); void Reset();
@ -35,4 +35,4 @@ public:
AddressInfo GetAbsoluteAddress(uint32_t address) override; AddressInfo GetAbsoluteAddress(uint32_t address) override;
void Serialize(Serializer& s) override; void Serialize(Serializer& s) override;
}; };

View file

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

View file

@ -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 //Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
_callstack.pop_front(); _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) void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
{ {
if(_callstack.empty()) { if (_callstack.empty())
{
return; return;
} }
@ -46,14 +49,18 @@ void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress)
uint32_t returnAddr = prevFrame.Return; 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 //Mismatch, pop that stack frame and add the new one
bool foundMatch = false; bool foundMatch = false;
for(int i = (int)_callstack.size() - 1; i >= 0; i--) { for (int i = (int)_callstack.size() - 1; i >= 0; i--)
if(destAddress == _callstack[i].Return) { {
if (destAddress == _callstack[i].Return)
{
//Found a matching stack frame, unstack until that point //Found a matching stack frame, unstack until that point
foundMatch = true; 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(); _callstack.pop_back();
_profiler->UnstackFunction(); _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 //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); DebugBreakHelper helper(_debugger);
int i = 0; int i = 0;
for(StackFrameInfo &info : _callstack) { for (StackFrameInfo& info : _callstack)
{
callstackArray[i] = info; callstackArray[i] = info;
i++; i++;
} }
@ -82,7 +92,8 @@ void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t &ca
int32_t CallstackManager::GetReturnAddress() int32_t CallstackManager::GetReturnAddress()
{ {
DebugBreakHelper helper(_debugger); DebugBreakHelper helper(_debugger);
if(_callstack.empty()) { if (_callstack.empty())
{
return -1; return -1;
} }
return _callstack.back().Return; return _callstack.back().Return;

View file

@ -16,10 +16,11 @@ public:
CallstackManager(Debugger* debugger); CallstackManager(Debugger* debugger);
~CallstackManager(); ~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 Pop(AddressInfo& dest, uint32_t destAddr);
void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize); void GetCallstack(StackFrameInfo* callstackArray, uint32_t& callstackSize);
int32_t GetReturnAddress(); int32_t GetReturnAddress();
Profiler* GetProfiler(); Profiler* GetProfiler();
}; };

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ private:
uint32_t _prgSize = 0; uint32_t _prgSize = 0;
uint32_t _codeSize = 0; uint32_t _codeSize = 0;
uint32_t _dataSize = 0; uint32_t _dataSize = 0;
void CalculateStats(); void CalculateStats();
public: public:
@ -34,10 +34,10 @@ public:
uint8_t GetCpuFlags(uint32_t absoluteAddr); uint8_t GetCpuFlags(uint32_t absoluteAddr);
CpuType GetCpuType(uint32_t absoluteAddr); CpuType GetCpuType(uint32_t absoluteAddr);
void SetCdlData(uint8_t *cdlData, uint32_t length); void SetCdlData(uint8_t* cdlData, uint32_t length);
void GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData); void GetCdlData(uint32_t offset, uint32_t length, uint8_t* cdlData);
uint8_t GetFlags(uint32_t addr); uint8_t GetFlags(uint32_t addr);
void MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags); void MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags);
void StripData(uint8_t* romBuffer, CdlStripOption flag); void StripData(uint8_t* romBuffer, CdlStripOption flag);
}; };

View file

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

View file

@ -53,7 +53,7 @@ private:
shared_ptr<InternalRegisters> _internalRegisters; shared_ptr<InternalRegisters> _internalRegisters;
shared_ptr<ControlManager> _controlManager; shared_ptr<ControlManager> _controlManager;
shared_ptr<DmaController> _dmaController; shared_ptr<DmaController> _dmaController;
shared_ptr<Msu1> _msu1; shared_ptr<Msu1> _msu1;
shared_ptr<Debugger> _debugger; shared_ptr<Debugger> _debugger;
@ -73,7 +73,7 @@ private:
shared_ptr<SpcHud> _spcHud; shared_ptr<SpcHud> _spcHud;
thread::id _emulationThreadId; thread::id _emulationThreadId;
atomic<uint32_t> _lockCounter; atomic<uint32_t> _lockCounter;
SimpleLock _runLock; SimpleLock _runLock;
SimpleLock _emulationLock; SimpleLock _emulationLock;
@ -124,7 +124,7 @@ public:
void PowerCycle(); void PowerCycle();
void PauseOnNextFrame(); void PauseOnNextFrame();
void Pause(); void Pause();
void Resume(); void Resume();
bool IsPaused(); bool IsPaused();
@ -141,8 +141,8 @@ public:
void Unlock(); void Unlock();
bool IsThreadPaused(); bool IsThreadPaused();
void Serialize(ostream &out, int compressionLevel = 1); void Serialize(ostream& out, int compressionLevel = 1);
void Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed = true); void Deserialize(istream& in, uint32_t fileFormatVersion, bool compressed = true);
shared_ptr<SoundMixer> GetSoundMixer(); shared_ptr<SoundMixer> GetSoundMixer();
shared_ptr<VideoRenderer> GetVideoRenderer(); shared_ptr<VideoRenderer> GetVideoRenderer();
@ -172,72 +172,84 @@ public:
bool IsDebugging(); bool IsDebugging();
thread::id GetEmulationThreadId(); thread::id GetEmulationThreadId();
bool IsRunning(); bool IsRunning();
bool IsRunAheadFrame(); bool IsRunAheadFrame();
uint32_t GetFrameCount(); uint32_t GetFrameCount();
double GetFps(); double GetFps();
void CopyRewindData(shared_ptr<Console> sourceConsole); void CopyRewindData(shared_ptr<Console> sourceConsole);
template<CpuType type> __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) template <CpuType type>
__forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessMemoryRead<type>(addr, value, opType); _debugger->ProcessMemoryRead<type>(addr, value, opType);
} }
} }
template<CpuType type> __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) template <CpuType type>
__forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessMemoryWrite<type>(addr, value, opType); _debugger->ProcessMemoryWrite<type>(addr, value, opType);
} }
} }
__forceinline void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType) __forceinline void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessPpuRead(addr, value, memoryType); _debugger->ProcessPpuRead(addr, value, memoryType);
} }
} }
__forceinline void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType) __forceinline void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessPpuWrite(addr, value, memoryType); _debugger->ProcessPpuWrite(addr, value, memoryType);
} }
} }
__forceinline void ProcessWorkRamRead(uint32_t addr, uint8_t value) __forceinline void ProcessWorkRamRead(uint32_t addr, uint8_t value)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessWorkRamRead(addr, value); _debugger->ProcessWorkRamRead(addr, value);
} }
} }
__forceinline void ProcessWorkRamWrite(uint32_t addr, uint8_t value) __forceinline void ProcessWorkRamWrite(uint32_t addr, uint8_t value)
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessWorkRamWrite(addr, value); _debugger->ProcessWorkRamWrite(addr, value);
} }
} }
template<CpuType cpuType> __forceinline void ProcessPpuCycle() template <CpuType cpuType>
__forceinline void ProcessPpuCycle()
{ {
if(_debugger) { if (_debugger)
{
_debugger->ProcessPpuCycle<cpuType>(); _debugger->ProcessPpuCycle<cpuType>();
} }
} }
__forceinline void DebugLog(string log) __forceinline void DebugLog(string log)
{ {
if(_debugger) { if (_debugger)
{
_debugger->Log(log); _debugger->Log(log);
} }
} }
template<CpuType type> void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template <CpuType type>
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type); void ProcessEvent(EventType type);
void BreakImmediately(BreakSource source); void BreakImmediately(BreakSource source);
}; };

View file

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

View file

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

View file

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

View file

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

View file

@ -19,7 +19,7 @@ class ControlManager : public ISerializable
private: private:
vector<IInputRecorder*> _inputRecorders; vector<IInputRecorder*> _inputRecorders;
vector<IInputProvider*> _inputProviders; vector<IInputProvider*> _inputProviders;
uint32_t _pollCounter; uint32_t _pollCounter;
uint32_t _inputConfigVersion; uint32_t _inputConfigVersion;
@ -54,11 +54,11 @@ public:
SystemActionManager* GetSystemActionManager(); SystemActionManager* GetSystemActionManager();
shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port); shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port);
vector<shared_ptr<BaseControlDevice>> GetControlDevices(); vector<shared_ptr<BaseControlDevice>> GetControlDevices();
static shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port, Console* console); static shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port, Console* console);
uint8_t Read(uint16_t addr); uint8_t Read(uint16_t addr);
void Write(uint16_t addr, uint8_t value); void Write(uint16_t addr, uint8_t value);
void Serialize(Serializer &s) override; void Serialize(Serializer& s) override;
}; };

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -29,11 +29,11 @@ private:
static constexpr uint32_t LegacyIrqVector = 0xFFFE; static constexpr uint32_t LegacyIrqVector = 0xFFFE;
static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4; static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4;
typedef void(Cpu::*Func)(); typedef void (Cpu::*Func)();
MemoryManager *_memoryManager = nullptr; MemoryManager* _memoryManager = nullptr;
DmaController *_dmaController = nullptr; DmaController* _dmaController = nullptr;
Console *_console = nullptr; Console* _console = nullptr;
bool _immediateMode = false; bool _immediateMode = false;
@ -47,9 +47,9 @@ private:
uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true); uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true);
uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true); uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true);
uint8_t GetOpCode(); uint8_t GetOpCode();
uint16_t GetResetVector(); uint16_t GetResetVector();
void UpdateIrqNmiFlags(); void UpdateIrqNmiFlags();
@ -59,7 +59,7 @@ private:
void IdleOrRead(); void IdleOrRead();
void IdleEndJump(); void IdleEndJump();
void IdleTakeBranch(); void IdleTakeBranch();
uint8_t ReadOperandByte(); uint8_t ReadOperandByte();
uint16_t ReadOperandWord(); uint16_t ReadOperandWord();
uint32_t ReadOperandLong(); uint32_t ReadOperandLong();
@ -71,9 +71,9 @@ private:
void SetSP(uint16_t sp); void SetSP(uint16_t sp);
void SetPS(uint8_t ps); void SetPS(uint8_t ps);
void SetRegister(uint8_t &reg, uint8_t value); void SetRegister(uint8_t& reg, uint8_t value);
void SetRegister(uint16_t &reg, uint16_t value, bool eightBitMode); void SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode);
void SetZeroNegativeFlags(uint16_t value); void SetZeroNegativeFlags(uint16_t value);
void SetZeroNegativeFlags(uint8_t value); void SetZeroNegativeFlags(uint8_t value);
@ -109,7 +109,7 @@ private:
void Sub8(uint8_t value); void Sub8(uint8_t value);
void Sub16(uint16_t value); void Sub16(uint16_t value);
void SBC(); void SBC();
//Branch instructions //Branch instructions
void BCC(); void BCC();
void BCS(); void BCS();
@ -122,7 +122,7 @@ private:
void BVC(); void BVC();
void BVS(); void BVS();
void BranchRelative(bool branch); void BranchRelative(bool branch);
//Set/clear flag instructions //Set/clear flag instructions
void CLC(); void CLC();
void CLD(); void CLD();
@ -146,7 +146,7 @@ private:
void DEC_Acc(); void DEC_Acc();
void INC_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); void IncDec(int8_t offset);
//Compare instructions //Compare instructions
@ -174,10 +174,14 @@ private:
void EOR(); void EOR();
void ORA(); void ORA();
template<typename T> T ShiftLeft(T value); template <typename T>
template<typename T> T RollLeft(T value); T ShiftLeft(T value);
template<typename T> T ShiftRight(T value); template <typename T>
template<typename T> T RollRight(T value); T RollLeft(T value);
template <typename T>
T ShiftRight(T value);
template <typename T>
T RollRight(T value);
//Shift operations //Shift operations
void ASL_Acc(); void ASL_Acc();
@ -213,10 +217,10 @@ private:
void PLY(); void PLY();
void PushRegister(uint16_t reg, bool eightBitMode); void PushRegister(uint16_t reg, bool eightBitMode);
void PullRegister(uint16_t &reg, bool eightBitMode); void PullRegister(uint16_t& reg, bool eightBitMode);
//Store/load instructions //Store/load instructions
void LoadRegister(uint16_t &reg, bool eightBitMode); void LoadRegister(uint16_t& reg, bool eightBitMode);
void StoreRegister(uint16_t val, bool eightBitMode); void StoreRegister(uint16_t val, bool eightBitMode);
void LDA(); void LDA();
@ -227,9 +231,10 @@ private:
void STX(); void STX();
void STY(); void STY();
void STZ(); void STZ();
//Test bits //Test bits
template<typename T> void TestBits(T value, bool alterZeroFlagOnly); template <typename T>
void TestBits(T value, bool alterZeroFlagOnly);
void BIT(); void BIT();
void TRB(); void TRB();
@ -282,7 +287,7 @@ private:
void AddrMode_BlkMov(); void AddrMode_BlkMov();
uint8_t ReadDirectOperandByte(); uint8_t ReadDirectOperandByte();
//Direct: d //Direct: d
void AddrMode_Dir(); void AddrMode_Dir();
//Direct Indexed: d,x //Direct Indexed: d,x
@ -291,7 +296,7 @@ private:
void AddrMode_DirIdxY(); void AddrMode_DirIdxY();
//Direct Indirect: (d) //Direct Indirect: (d)
void AddrMode_DirInd(); void AddrMode_DirInd();
//Direct Indexed Indirect: (d,x) //Direct Indexed Indirect: (d,x)
void AddrMode_DirIdxIndX(); void AddrMode_DirIdxIndX();
//Direct Indirect Indexed: (d),y //Direct Indirect Indexed: (d),y
@ -313,12 +318,12 @@ private:
void AddrMode_StkRel(); void AddrMode_StkRel();
void AddrMode_StkRelIndIdxY(); void AddrMode_StkRelIndIdxY();
void RunOp(); void RunOp();
public: public:
#ifndef DUMMYCPU #ifndef DUMMYCPU
Cpu(Console *console); Cpu(Console* console);
#else #else
DummyCpu(Console* console, CpuType type); DummyCpu(Console* console, CpuType type);
#endif #endif
@ -334,7 +339,7 @@ public:
bool GetCpuProcFlag(ProcFlags::ProcFlags flag); bool GetCpuProcFlag(ProcFlags::ProcFlags flag);
uint64_t GetCycleCount(); uint64_t GetCycleCount();
template<uint64_t value> template <uint64_t value>
void IncreaseCycleCount(); void IncreaseCycleCount();
void SetNmiFlag(bool nmiFlag); void SetNmiFlag(bool nmiFlag);
@ -345,7 +350,7 @@ public:
void ClearIrqSource(IrqSource source); void ClearIrqSource(IrqSource source);
// Inherited via ISerializable // Inherited via ISerializable
void Serialize(Serializer &s) override; void Serialize(Serializer& s) override;
void SetReg(CpuRegister reg, uint16_t value); void SetReg(CpuRegister reg, uint16_t value);
void SetCpuProcFlag(ProcFlags::ProcFlags flag, bool set); void SetCpuProcFlag(ProcFlags::ProcFlags flag, bool set);
@ -377,10 +382,10 @@ public:
void SetReg(CpuRegister reg, uint16_t value); void SetReg(CpuRegister reg, uint16_t value);
template<uint64_t count> template <uint64_t count>
void Cpu::IncreaseCycleCount() void Cpu::IncreaseCycleCount()
{ {
_state.CycleCount += count; _state.CycleCount += count;
} }
#endif #endif

View file

@ -10,7 +10,7 @@
class CpuBwRamHandler : public IMemoryHandler class CpuBwRamHandler : public IMemoryHandler
{ {
private: private:
IMemoryHandler * _handler; IMemoryHandler* _handler;
Sa1State* _state; Sa1State* _state;
Sa1* _sa1; Sa1* _sa1;
@ -24,9 +24,12 @@ public:
uint8_t Read(uint32_t addr) override uint8_t Read(uint32_t addr) override
{ {
if(_state->CharConvDmaActive) { if (_state->CharConvDmaActive)
{
return _sa1->ReadCharConvertType1(addr); return _sa1->ReadCharConvertType1(addr);
} else { }
else
{
return _handler->Read(addr); return _handler->Read(addr);
} }
} }
@ -36,7 +39,7 @@ public:
return Read(addr); 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); _handler->PeekBlock(addr, output);
} }
@ -50,4 +53,4 @@ public:
{ {
return _handler->GetAbsoluteAddress(address); return _handler->GetAbsoluteAddress(address);
} }
}; };

View file

@ -36,14 +36,16 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
_codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get();
_settings = debugger->GetConsole()->GetSettings().get(); _settings = debugger->GetConsole()->GetSettings().get();
_memoryManager = debugger->GetConsole()->GetMemoryManager().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)); _callstackManager.reset(new CallstackManager(debugger));
_breakpointManager.reset(new BreakpointManager(debugger, cpuType, _eventManager.get())); _breakpointManager.reset(new BreakpointManager(debugger, cpuType, _eventManager.get()));
_step.reset(new StepRequest()); _step.reset(new StepRequest());
_assembler.reset(new Assembler(_debugger->GetLabelManager())); _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 //Enable breaking on uninit reads when debugger is opened at power on
_enableBreakOnUninitRead = true; _enableBreakOnUninitRead = true;
} }
@ -59,26 +61,34 @@ void CpuDebugger::Reset()
void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{ {
AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr); AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type }; MemoryOperationInfo operation = {addr, value, type};
CpuState state = GetState(); CpuState state = GetState();
BreakSource breakSource = BreakSource::Unspecified; BreakSource breakSource = BreakSource::Unspecified;
if(type == MemoryOperationType::ExecOpCode) { if (type == MemoryOperationType::ExecOpCode)
bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(_cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled); {
if(addressInfo.Address >= 0) { bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(
if(addressInfo.Type == SnesMemoryType::PrgRom) { _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)); 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; flags |= CdlFlags::SubEntryPoint;
} }
_codeDataLogger->SetFlags(addressInfo.Address, flags); _codeDataLogger->SetFlags(addressInfo.Address, flags);
} }
if(needDisassemble) { if (needDisassemble)
_disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), _cpuType); {
_disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8),
_cpuType);
} }
} }
if(_traceLogger->IsCpuLogged(_cpuType)) { if (_traceLogger->IsCpuLogged(_cpuType))
{
_debugger->GetState(_debugState, true); _debugger->GetState(_debugState, true);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType); 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; uint32_t pc = (state.K << 16) | state.PC;
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) { if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC)
{
//JSR, JSL //JSR, JSL
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType); uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF); uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter); AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc); AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc);
_callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None); _callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc,
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) { StackFrameFlags::None);
}
else if (_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40)
{
//RTS, RTL, RTI //RTS, RTL, RTI
_callstackManager->Pop(addressInfo, pc); _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) //RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_step->StepCount = 0; _step->StepCount = 0;
} }
@ -106,47 +122,72 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevOpCode = value; _prevOpCode = value;
_prevProgramCounter = pc; _prevProgramCounter = pc;
if(_step->StepCount > 0) { if (_step->StepCount > 0)
{
_step->StepCount--; _step->StepCount--;
} }
if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled)) { if (_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled))
if(value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) { {
if (value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB)
{
//Break on BRK/STP/WDM/COP //Break on BRK/STP/WDM/COP
if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { if (value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk))
{
breakSource = BreakSource::BreakOnBrk; breakSource = BreakSource::BreakOnBrk;
_step->StepCount = 0; _step->StepCount = 0;
} else if(value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) { }
else if (value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop))
{
breakSource = BreakSource::BreakOnCop; breakSource = BreakSource::BreakOnCop;
_step->StepCount = 0; _step->StepCount = 0;
} else if(value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) { }
else if (value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm))
{
breakSource = BreakSource::BreakOnWdm; breakSource = BreakSource::BreakOnWdm;
_step->StepCount = 0; _step->StepCount = 0;
} else if(value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) { }
else if (value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp))
{
breakSource = BreakSource::BreakOnStp; breakSource = BreakSource::BreakOnStp;
_step->StepCount = 0; _step->StepCount = 0;
} }
} }
} }
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
} else if(type == MemoryOperationType::ExecOperand) { }
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) { else if (type == MemoryOperationType::ExecOperand)
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); {
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()); _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
} else { }
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) { else
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); {
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 //Memory access was a read on an uninitialized memory address
if(_enableBreakOnUninitRead) { if (_enableBreakOnUninitRead)
if(_memoryAccessCounter->GetReadCount(addressInfo) == 1) { {
if (_memoryAccessCounter->GetReadCount(addressInfo) == 1)
{
//Only warn the first time //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; breakSource = BreakSource::BreakOnUninitMemoryRead;
_step->StepCount = 0; _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); _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) void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{ {
AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr); AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type }; MemoryOperationInfo operation = {addr, value, type};
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) { if (addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type ==
SnesMemoryType::SaveRam))
{
_disassembler->InvalidateCache(addressInfo, _cpuType); _disassembler->InvalidateCache(addressInfo, _cpuType);
} }
if(IsRegister(addr)) { if (IsRegister(addr))
{
_eventManager->AddEvent(DebugEventType::Register, operation); _eventManager->AddEvent(DebugEventType::Register, operation);
} }
@ -186,25 +232,39 @@ void CpuDebugger::Run()
void CpuDebugger::Step(int32_t stepCount, StepType type) void CpuDebugger::Step(int32_t stepCount, StepType type)
{ {
StepRequest step; 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) //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; step.PpuStepCount = 1;
} else { }
switch(type) { else
case StepType::Step: step.StepCount = stepCount; break; {
case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; switch (type)
case StepType::StepOver: {
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) { case StepType::Step: step.StepCount = stepCount;
//JSR, JSL, BRK, COP, MVP, MVN break;
step.BreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, _cpuType)) & 0xFFFF); case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress();
} else { break;
//For any other instruction, step over is the same as step into case StepType::StepOver:
step.StepCount = 1; if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode ==
} 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54)
break; {
//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::PpuStep: step.PpuStepCount = stepCount;
case StepType::SpecificScanline: step.BreakScanline = stepCount; break; break;
case StepType::SpecificScanline: step.BreakScanline = stepCount;
break;
} }
} }
_step.reset(new StepRequest(step)); _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 src = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc); AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc);
AddressInfo dest = GetMemoryMappings().GetAbsoluteAddress(currentPc); 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); _eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
} }
void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle)
{ {
if(_step->PpuStepCount > 0) { if (_step->PpuStepCount > 0)
{
_step->PpuStepCount--; _step->PpuStepCount--;
if(_step->PpuStepCount == 0) { if (_step->PpuStepCount == 0)
{
_debugger->SleepUntilResume(BreakSource::PpuStep); _debugger->SleepUntilResume(BreakSource::PpuStep);
} }
} }
if(cycle == 0 && scanline == _step->BreakScanline) { if (cycle == 0 && scanline == _step->BreakScanline)
{
_step->BreakScanline = -1; _step->BreakScanline = -1;
_debugger->SleepUntilResume(BreakSource::PpuStep); _debugger->SleepUntilResume(BreakSource::PpuStep);
} }
@ -236,18 +300,24 @@ void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle)
MemoryMappings& CpuDebugger::GetMemoryMappings() MemoryMappings& CpuDebugger::GetMemoryMappings()
{ {
if(_cpuType == CpuType::Cpu) { if (_cpuType == CpuType::Cpu)
{
return *_memoryManager->GetMemoryMappings(); return *_memoryManager->GetMemoryMappings();
} else { }
else
{
return *_sa1->GetMemoryMappings(); return *_sa1->GetMemoryMappings();
} }
} }
CpuState CpuDebugger::GetState() CpuState CpuDebugger::GetState()
{ {
if(_cpuType == CpuType::Cpu) { if (_cpuType == CpuType::Cpu)
{
return _cpu->GetState(); return _cpu->GetState();
} else { }
else
{
return _sa1->GetCpuState(); return _sa1->GetCpuState();
} }
} }
@ -275,4 +345,4 @@ shared_ptr<CallstackManager> CpuDebugger::GetCallstackManager()
BreakpointManager* CpuDebugger::GetBreakpointManager() BreakpointManager* CpuDebugger::GetBreakpointManager()
{ {
return _breakpointManager.get(); return _breakpointManager.get();
} }

View file

@ -62,4 +62,4 @@ public:
shared_ptr<Assembler> GetAssembler(); shared_ptr<Assembler> GetAssembler();
shared_ptr<CallstackManager> GetCallstackManager(); shared_ptr<CallstackManager> GetCallstackManager();
BreakpointManager* GetBreakpointManager(); BreakpointManager* GetBreakpointManager();
}; };

View file

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

View file

@ -13,7 +13,7 @@ class CpuDisUtils
{ {
private: private:
static uint8_t OpSize[0x1F]; 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 uint8_t GetOpSize(AddrMode addrMode, uint8_t flags);
static bool HasEffectiveAddress(AddrMode addrMode); static bool HasEffectiveAddress(AddrMode addrMode);
@ -22,9 +22,10 @@ public:
static string OpName[256]; static string OpName[256];
static AddrMode OpMode[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 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 enum class AddrMode : uint8_t
@ -35,15 +36,20 @@ enum class AddrMode : uint8_t
ImmX, ImmX,
ImmM, ImmM,
Abs, Abs,
AbsIdxXInd, //JMP/JSR only AbsIdxXInd,
//JMP/JSR only
AbsIdxX, AbsIdxX,
AbsIdxY, AbsIdxY,
AbsInd, //JMP only AbsInd,
AbsIndLng, //JML only //JMP only
AbsIndLng,
//JML only
AbsLngIdxX, AbsLngIdxX,
AbsLng, AbsLng,
AbsJmp, //JSR/JMP only AbsJmp,
AbsLngJmp, //JSL/JMP only //JSR/JMP only
AbsLngJmp,
//JSL/JMP only
Acc, Acc,
BlkMov, BlkMov,
DirIdxIndX, DirIdxIndX,
@ -60,4 +66,4 @@ enum class AddrMode : uint8_t
Stk, Stk,
StkRel, StkRel,
StkRelIndIdxY StkRelIndIdxY
}; };

View file

@ -15,7 +15,7 @@ struct CpuState
uint16_t A; uint16_t A;
uint16_t X; uint16_t X;
uint16_t Y; uint16_t Y;
/* 16-bit stack pointer */ /* 16-bit stack pointer */
uint16_t SP; uint16_t SP;
@ -88,4 +88,3 @@ enum class IrqSource
Ppu = 1, Ppu = 1,
Coprocessor = 2 Coprocessor = 2
}; };

View file

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

View file

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

View file

@ -13,9 +13,9 @@ class Cx4 : public BaseCoprocessor
private: private:
static constexpr int DataRamSize = 0xC00; static constexpr int DataRamSize = 0xC00;
Console *_console; Console* _console;
MemoryManager *_memoryManager; MemoryManager* _memoryManager;
Cpu *_cpu; Cpu* _cpu;
MemoryMappings _mappings; MemoryMappings _mappings;
double _clockRatio; double _clockRatio;
@ -119,7 +119,7 @@ public:
uint8_t Read(uint32_t addr) override; uint8_t Read(uint32_t addr) override;
void Write(uint32_t addr, uint8_t value) 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; 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;
@ -131,4 +131,4 @@ public:
Cx4State GetState(); Cx4State GetState();
void SetReg(Cx4Register reg, uint32_t value); void SetReg(Cx4Register reg, uint32_t value);
}; };

View file

@ -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; addr = (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF;
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr); 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); 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, CdlFlags::Code | CdlFlags::Cx4);
_codeDataLogger->SetFlags(addressInfo.Address + 1, 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); _disassembler->BuildCache(addressInfo, 0, CpuType::Cx4);
if(_traceLogger->IsCpuLogged(CpuType::Cx4)) { if (_traceLogger->IsCpuLogged(CpuType::Cx4))
{
DebugState debugState; DebugState debugState;
_debugger->GetState(debugState, true); _debugger->GetState(debugState, true);
@ -65,14 +69,18 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevProgramCounter = addr; _prevProgramCounter = addr;
if(_step->StepCount > 0) { if (_step->StepCount > 0)
{
_step->StepCount--; _step->StepCount--;
} }
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
_memoryAccessCounter->ProcessMemoryExec(opCodeHighAddr, _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); _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Cx4);
} }
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); _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) void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{ {
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr); 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); _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
} }
@ -98,17 +106,19 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type)
{ {
StepRequest step; StepRequest step;
switch(type) { switch (type)
case StepType::Step: step.StepCount = stepCount; break; {
case StepType::Step: step.StepCount = stepCount;
break;
case StepType::StepOut: case StepType::StepOut:
case StepType::StepOver: case StepType::StepOver:
step.StepCount = 1; step.StepCount = 1;
break; break;
case StepType::SpecificScanline: case StepType::SpecificScanline:
case StepType::PpuStep: case StepType::PpuStep:
break; break;
} }
_step.reset(new StepRequest(step)); _step.reset(new StepRequest(step));
@ -117,4 +127,4 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type)
BreakpointManager* Cx4Debugger::GetBreakpointManager() BreakpointManager* Cx4Debugger::GetBreakpointManager()
{ {
return _breakpointManager.get(); return _breakpointManager.get();
} }

View file

@ -40,4 +40,4 @@ public:
void Run(); void Run();
void Step(int32_t stepCount, StepType type); void Step(int32_t stepCount, StepType type);
BreakpointManager* GetBreakpointManager(); BreakpointManager* GetBreakpointManager();
}; };

View file

@ -5,7 +5,8 @@
#include "../Utilities/HexUtilities.h" #include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.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)); 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 param1 = info.GetByteCode()[1] & 0x03;
uint8_t param2 = info.GetByteCode()[0] & 0xFF; uint8_t param2 = info.GetByteCode()[0] & 0xFF;
auto writeSrc = [&str, param2]() -> void { auto writeSrc = [&str, param2]() -> void
switch(param2 & 0x7F) { {
case 0x00: str.Write("A"); break; switch (param2 & 0x7F)
case 0x01: str.Write("MULTH"); break; {
case 0x02: str.Write("MULTL"); break; case 0x00: str.Write("A");
case 0x03: str.Write("MDR"); break; break;
case 0x08: str.Write("ROM"); break; case 0x01: str.Write("MULTH");
case 0x0C: str.Write("RAM"); break; break;
case 0x13: str.Write("MAR"); break; case 0x02: str.Write("MULTL");
case 0x1C: str.Write("DPR"); break; break;
case 0x20: str.Write("PC"); break; case 0x03: str.Write("MDR");
case 0x28: str.Write("P"); break; 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 0x50: str.Write("#$000000");
case 0x51: str.Write("#$FFFFFF"); break; break;
case 0x52: str.Write("#$00FF00"); break; case 0x51: str.Write("#$FFFFFF");
case 0x53: str.Write("#$FF0000"); break; break;
case 0x54: str.Write("#$00FFFF"); break; case 0x52: str.Write("#$00FF00");
case 0x55: str.Write("#$FFFF00"); break; break;
case 0x56: str.Write("#$800000"); break; case 0x53: str.Write("#$FF0000");
case 0x57: str.Write("#$7FFFFF"); break; break;
case 0x58: str.Write("#$008000"); break; case 0x54: str.Write("#$00FFFF");
case 0x59: str.Write("#$007FFF"); break; break;
case 0x5A: str.Write("#$FF7FFF"); break; case 0x55: str.Write("#$FFFF00");
case 0x5B: str.Write("#$FFFF7F"); break; break;
case 0x5C: str.Write("#$010000"); break; case 0x56: str.Write("#$800000");
case 0x5D: str.Write("#$FEFFFF"); break; break;
case 0x5E: str.Write("#$000100"); break; case 0x57: str.Write("#$7FFFFF");
case 0x5F: str.Write("#$00FEFF"); break; 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 0x60:
case 0x61: case 0x71: str.Write("R1"); break; case 0x70: str.Write("R0");
case 0x62: case 0x72: str.Write("R2"); break; break;
case 0x63: case 0x73: str.Write("R3"); break; case 0x61:
case 0x64: case 0x74: str.Write("R4"); break; case 0x71: str.Write("R1");
case 0x65: case 0x75: str.Write("R5"); break; break;
case 0x66: case 0x76: str.Write("R6"); break; case 0x62:
case 0x67: case 0x77: str.Write("R7"); break; case 0x72: str.Write("R2");
case 0x68: case 0x78: str.Write("R8"); break; break;
case 0x69: case 0x79: str.Write("R9"); break; case 0x63:
case 0x6A: case 0x7A: str.Write("R10"); break; case 0x73: str.Write("R3");
case 0x6B: case 0x7B: str.Write("R11"); break; break;
case 0x6C: case 0x7C: str.Write("R12"); break; case 0x64:
case 0x6D: case 0x7D: str.Write("R13"); break; case 0x74: str.Write("R4");
case 0x6E: case 0x7E: str.Write("R14"); break; break;
case 0x6F: case 0x7F: str.Write("R15"); 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 { auto writeDest = [&str, param1]() -> void
switch(param1) { {
case 0: str.Write("A"); break; switch (param1)
case 1: str.Write("MDR"); break; {
case 2: str.Write("MAR"); break; case 0: str.Write("A");
case 3: str.Write("P"); break; break;
case 1: str.Write("MDR");
break;
case 2: str.Write("MAR");
break;
case 3: str.Write("P");
break;
} }
}; };
auto writeShiftedA = [&str, param1]() -> void { auto writeShiftedA = [&str, param1]() -> void
switch(param1) { {
case 0: str.Write("A"); break; switch (param1)
case 1: str.Write("(A << 1)"); break; {
case 2: str.Write("(A << 8)"); break; case 0: str.Write("A");
case 3: str.Write("(A << 16)"); break; 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 { auto writeBranchTarget = [&str, param1, param2]() -> void
if(param1) { {
if (param1)
{
//Far jump //Far jump
str.Write("P:"); str.Write("P:");
} }
str.WriteAll('$', HexUtilities::ToHex(param2)); 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; switch (op)
case 0x14: str.Write("BMI "); writeBranchTarget(); break; {
case 0x18: str.Write("BVS "); writeBranchTarget(); break; case 0x00: str.Write("NOP");
case 0x1C: str.Write("WAIT"); break; 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 0x10: str.Write("BCS ");
case 0x24: writeBranchTarget();
str.Write("SKIP"); break;
switch(param1) { case 0x14: str.Write("BMI ");
case 0: str.Write('V'); break; writeBranchTarget();
case 1: str.Write('C'); break; break;
case 2: str.Write('Z'); break; case 0x18: str.Write("BVS ");
case 3: str.Write('N'); break; writeBranchTarget();
} break;
str.Write((param2 & 0x01) ? 'S' : 'C'); case 0x1C: str.Write("WAIT");
break;
case 0x20: str.Write("???");
break;
case 0x24:
str.Write("SKIP");
switch (param1)
{
case 0: str.Write('V');
break; break;
case 1: str.Write('C');
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; break;
case 0x5C: str.Write("???"); break; case 2: str.Write('Z');
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; break;
case 3: str.Write('N');
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; break;
case 0xE4: str.Write("???"); break; }
case 0xE8: str.WriteAll("WRRAM A,RAM:", '0' + param1); break; str.Write((param2 & 0x01) ? 'S' : 'C');
case 0xEC: str.WriteAll("WRRAM DPR+#$", HexUtilities::ToHex(param2), ",RAM:", '0' + param1); break; break;
case 0xF0: str.WriteAll("SWAP A,R", std::to_string(param2 & 0x0F)); break; case 0x28: str.Write("JSR ");
case 0xF4: str.Write("???"); break; writeBranchTarget();
case 0xF8: str.Write("???"); break; break;
case 0xFC: str.Write("STOP"); 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(); out += str.ToString();

View file

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

View file

@ -48,7 +48,7 @@ struct Cx4State
uint8_t PC; uint8_t PC;
//Accumulator //Accumulator
uint32_t A; uint32_t A;
//Page register //Page register
uint16_t P; uint16_t P;
@ -76,7 +76,7 @@ struct Cx4State
bool Stopped; bool Stopped;
bool Locked; bool Locked;
bool IrqDisabled; bool IrqDisabled;
bool SingleRom; bool SingleRom;
uint8_t RomAccessDelay; uint8_t RomAccessDelay;
@ -87,4 +87,4 @@ struct Cx4State
Cx4Cache Cache; Cx4Cache Cache;
Cx4Suspend Suspend; Cx4Suspend Suspend;
uint8_t Vectors[0x20]; uint8_t Vectors[0x20];
}; };

View file

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

View file

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

View file

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

View file

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

View file

@ -241,7 +241,7 @@ enum class BreakSource
BreakOnWdm = 5, BreakOnWdm = 5,
BreakOnStp = 6, BreakOnStp = 6,
BreakOnUninitMemoryRead = 7, BreakOnUninitMemoryRead = 7,
GbInvalidOamAccess = 8, GbInvalidOamAccess = 8,
GbInvalidVramAccess = 9, GbInvalidVramAccess = 9,
GbDisableLcdOutsideVblank = 10, GbDisableLcdOutsideVblank = 10,

View file

@ -7,14 +7,15 @@ class DebugUtilities
public: public:
static SnesMemoryType GetCpuMemoryType(CpuType type) static SnesMemoryType GetCpuMemoryType(CpuType type)
{ {
switch(type) { switch (type)
case CpuType::Cpu: return SnesMemoryType::CpuMemory; {
case CpuType::Spc: return SnesMemoryType::SpcMemory; case CpuType::Cpu: return SnesMemoryType::CpuMemory;
case CpuType::NecDsp: return SnesMemoryType::NecDspMemory; case CpuType::Spc: return SnesMemoryType::SpcMemory;
case CpuType::Sa1: return SnesMemoryType::Sa1Memory; case CpuType::NecDsp: return SnesMemoryType::NecDspMemory;
case CpuType::Gsu: return SnesMemoryType::GsuMemory; case CpuType::Sa1: return SnesMemoryType::Sa1Memory;
case CpuType::Cx4: return SnesMemoryType::Cx4Memory; case CpuType::Gsu: return SnesMemoryType::GsuMemory;
case CpuType::Gameboy: return SnesMemoryType::GameboyMemory; case CpuType::Cx4: return SnesMemoryType::Cx4Memory;
case CpuType::Gameboy: return SnesMemoryType::GameboyMemory;
} }
throw std::runtime_error("Invalid CPU type"); throw std::runtime_error("Invalid CPU type");
@ -22,41 +23,42 @@ public:
static CpuType ToCpuType(SnesMemoryType type) static CpuType ToCpuType(SnesMemoryType type)
{ {
switch(type) { switch (type)
case SnesMemoryType::SpcMemory: {
case SnesMemoryType::SpcRam: case SnesMemoryType::SpcMemory:
case SnesMemoryType::SpcRom: case SnesMemoryType::SpcRam:
return CpuType::Spc; case SnesMemoryType::SpcRom:
return CpuType::Spc;
case SnesMemoryType::GsuMemory: case SnesMemoryType::GsuMemory:
case SnesMemoryType::GsuWorkRam: case SnesMemoryType::GsuWorkRam:
return CpuType::Gsu; return CpuType::Gsu;
case SnesMemoryType::Sa1InternalRam: case SnesMemoryType::Sa1InternalRam:
case SnesMemoryType::Sa1Memory: case SnesMemoryType::Sa1Memory:
return CpuType::Sa1; return CpuType::Sa1;
case SnesMemoryType::DspDataRam: case SnesMemoryType::DspDataRam:
case SnesMemoryType::DspDataRom: case SnesMemoryType::DspDataRom:
case SnesMemoryType::DspProgramRom: case SnesMemoryType::DspProgramRom:
return CpuType::NecDsp; return CpuType::NecDsp;
case SnesMemoryType::Cx4DataRam: case SnesMemoryType::Cx4DataRam:
case SnesMemoryType::Cx4Memory: case SnesMemoryType::Cx4Memory:
return CpuType::Cx4; 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;
default: case SnesMemoryType::GbPrgRom:
return CpuType::Cpu; 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"); throw std::runtime_error("Invalid CPU type");
@ -69,30 +71,32 @@ public:
static bool IsPpuMemory(SnesMemoryType memType) static bool IsPpuMemory(SnesMemoryType memType)
{ {
switch(memType) { switch (memType)
case SnesMemoryType::VideoRam: {
case SnesMemoryType::SpriteRam: case SnesMemoryType::VideoRam:
case SnesMemoryType::CGRam: case SnesMemoryType::SpriteRam:
case SnesMemoryType::GbVideoRam: case SnesMemoryType::CGRam:
case SnesMemoryType::GbSpriteRam: case SnesMemoryType::GbVideoRam:
return true; case SnesMemoryType::GbSpriteRam:
return true;
default: default:
return false; return false;
} }
} }
static bool IsRomMemory(SnesMemoryType memType) static bool IsRomMemory(SnesMemoryType memType)
{ {
switch(memType) { switch (memType)
case SnesMemoryType::PrgRom: {
case SnesMemoryType::GbPrgRom: case SnesMemoryType::PrgRom:
case SnesMemoryType::GbBootRom: case SnesMemoryType::GbPrgRom:
case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram case SnesMemoryType::GbBootRom:
return true; case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram
return true;
default: default:
return false; return false;
} }
} }
@ -100,4 +104,4 @@ public:
{ {
return CpuType::Gameboy; return CpuType::Gameboy;
} }
}; };

File diff suppressed because it is too large Load diff

View file

@ -75,7 +75,7 @@ private:
shared_ptr<LabelManager> _labelManager; shared_ptr<LabelManager> _labelManager;
unique_ptr<ExpressionEvaluator> _watchExpEval[(int)DebugUtilities::GetLastCpuType() + 1]; unique_ptr<ExpressionEvaluator> _watchExpEval[(int)DebugUtilities::GetLastCpuType() + 1];
SimpleLock _logLock; SimpleLock _logLock;
std::list<string> _debuggerLog; std::list<string> _debuggerLog;
@ -84,7 +84,7 @@ private:
atomic<uint32_t> _suspendRequestCount; atomic<uint32_t> _suspendRequestCount;
bool _waitForBreakResume = false; bool _waitForBreakResume = false;
void Reset(); void Reset();
public: public:
@ -92,10 +92,10 @@ public:
~Debugger(); ~Debugger();
void Release(); void Release();
template<CpuType type> template <CpuType type>
void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType);
template<CpuType type> template <CpuType type>
void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType);
void ProcessWorkRamRead(uint32_t addr, uint8_t value); void ProcessWorkRamRead(uint32_t addr, uint8_t value);
@ -104,15 +104,15 @@ public:
void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType); void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType); void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
template<CpuType cpuType> template <CpuType cpuType>
void ProcessPpuCycle(); void ProcessPpuCycle();
template<CpuType type> template <CpuType type>
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type); 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 Run();
void Step(CpuType cpuType, int32_t stepCount, StepType type); void Step(CpuType cpuType, int32_t stepCount, StepType type);
@ -124,7 +124,8 @@ public:
void BreakImmediately(BreakSource source); 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 SleepUntilResume(BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1);
void GetState(DebugState& state, bool partialPpuState); void GetState(DebugState& state, bool partialPpuState);
@ -143,15 +144,15 @@ public:
AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType); AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType);
void GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData); 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 MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags);
void RefreshCodeCache(); void RefreshCodeCache();
void RebuildPrgCache(CpuType cpuType); void RebuildPrgCache(CpuType cpuType);
void SetBreakpoints(Breakpoint breakpoints[], uint32_t length); void SetBreakpoints(Breakpoint breakpoints[], uint32_t length);
void GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes); void GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes);
void Log(string message); void Log(string message);
string GetLog(); string GetLog();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,16 +20,16 @@ private:
public: public:
DisassemblyInfo(); 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); void Initialize(uint32_t cpuAddress, uint8_t cpuFlags, CpuType type, MemoryDumper* memoryDumper);
bool IsInitialized(); bool IsInitialized();
bool IsValid(uint8_t cpuFlags); bool IsValid(uint8_t cpuFlags);
void Reset(); 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(); CpuType GetCpuType();
uint8_t GetOpCode(); uint8_t GetOpCode();
uint8_t GetOpSize(); uint8_t GetOpSize();
@ -37,7 +37,7 @@ public:
uint8_t* GetByteCode(); uint8_t* GetByteCode();
void GetByteCode(uint8_t copyBuffer[4]); 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 uint8_t GetOpSize(uint8_t opCode, uint8_t flags, CpuType type);
static bool IsJumpToSub(uint8_t opCode, CpuType type); static bool IsJumpToSub(uint8_t opCode, CpuType type);
@ -46,7 +46,7 @@ public:
bool IsUnconditionalJump(); bool IsUnconditionalJump();
void UpdateCpuFlags(uint8_t& cpuFlags); void UpdateCpuFlags(uint8_t& cpuFlags);
int32_t GetEffectiveAddress(Console *console, void *cpuState, CpuType type); int32_t GetEffectiveAddress(Console* console, void* cpuState, CpuType type);
uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper *memoryDumper, SnesMemoryType memType, uint8_t &valueSize); uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper* memoryDumper, SnesMemoryType memType,
uint8_t& valueSize);
}; };

View file

@ -5,19 +5,21 @@
#include "MessageManager.h" #include "MessageManager.h"
#include "../Utilities/Serializer.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] = { static constexpr uint8_t _transferOffset[8][4] = {
{ 0, 0, 0, 0 }, { 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 } {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; _memoryManager = memoryManager;
Reset(); Reset();
for(int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++)
for(int i = 0; i <= 0x0A; i++) { {
for (int i = 0; i <= 0x0A; i++)
{
Write(0x4300 | i | (j << 4), 0xFF); Write(0x4300 | i | (j << 4), 0xFF);
} }
} }
@ -33,36 +35,47 @@ void DmaController::Reset()
_dmaPending = false; _dmaPending = false;
_needToProcess = false; _needToProcess = false;
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
{
_channel[i].DmaActive = false; _channel[i].DmaActive = false;
} }
} }
void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA) void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA)
{ {
if(fromBtoA) { if (fromBtoA)
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) { {
if (addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA))
{
uint8_t valToWrite = _memoryManager->ReadDma(addressBusB, false); uint8_t valToWrite = _memoryManager->ReadDma(addressBusB, false);
_memoryManager->WriteDma(addressBusA, valToWrite, true); _memoryManager->WriteDma(addressBusA, valToWrite, true);
} else { }
else
{
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid //$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
_memoryManager->WriteDma(addressBusA, 0xFF, true); _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); uint8_t valToWrite = _memoryManager->ReadDma(addressBusA, true);
_memoryManager->WriteDma(addressBusB, valToWrite, false); _memoryManager->WriteDma(addressBusB, valToWrite, false);
} else { }
else
{
//WRAM->$2180 does not cause a write to occur //WRAM->$2180 does not cause a write to occur
_memoryManager->IncMasterClock8(); _memoryManager->IncMasterClock8();
} }
} }
} }
void DmaController::RunDma(DmaChannelConfig &channel) void DmaController::RunDma(DmaChannelConfig& channel)
{ {
if(!channel.DmaActive) { if (!channel.DmaActive)
{
return; return;
} }
@ -70,10 +83,11 @@ void DmaController::RunDma(DmaChannelConfig &channel)
_memoryManager->IncMasterClock8(); _memoryManager->IncMasterClock8();
ProcessPendingTransfers(); ProcessPendingTransfers();
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode]; const uint8_t* transferOffsets = _transferOffset[channel.TransferMode];
uint8_t i = 0; uint8_t i = 0;
do { do
{
//Manual DMA transfers run to the end of the transfer when started //Manual DMA transfers run to the end of the transfer when started
CopyDmaByte( CopyDmaByte(
(channel.SrcBank << 16) | channel.SrcAddress, (channel.SrcBank << 16) | channel.SrcAddress,
@ -81,14 +95,16 @@ void DmaController::RunDma(DmaChannelConfig &channel)
channel.InvertDirection channel.InvertDirection
); );
if(!channel.FixedTransfer) { if (!channel.FixedTransfer)
{
channel.SrcAddress += channel.Decrement ? -1 : 1; channel.SrcAddress += channel.Decrement ? -1 : 1;
} }
channel.TransferSize--; channel.TransferSize--;
i++; i++;
ProcessPendingTransfers(); ProcessPendingTransfers();
} while(channel.TransferSize > 0 && channel.DmaActive); }
while (channel.TransferSize > 0 && channel.DmaActive);
channel.DmaActive = false; channel.DmaActive = false;
} }
@ -97,31 +113,37 @@ bool DmaController::InitHdmaChannels()
{ {
_hdmaInitPending = false; _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 //Reset internal flags on every frame, whether or not the channels are enabled
_channel[i].HdmaFinished = false; _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 //No channels are enabled, no more processing needs to be done
UpdateNeedToProcessFlag(); UpdateNeedToProcessFlag();
return false; return false;
} }
bool needSync = !HasActiveDmaChannel(); bool needSync = !HasActiveDmaChannel();
if(needSync) { if (needSync)
{
SyncStartDma(); SyncStartDma();
} }
_memoryManager->IncMasterClock8(); _memoryManager->IncMasterClock8();
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
DmaChannelConfig &ch = _channel[i]; {
DmaChannelConfig& ch = _channel[i];
//Set DoTransfer to true for all channels if any HDMA channel is enabled //Set DoTransfer to true for all channels if any HDMA channel is enabled
ch.DoTransfer = true; ch.DoTransfer = true;
if(_hdmaChannels & (1 << i)) { if (_hdmaChannels & (1 << i))
{
//"1. Copy AAddress into Address." //"1. Copy AAddress into Address."
ch.HdmaTableAddress = ch.SrcAddress; ch.HdmaTableAddress = ch.SrcAddress;
ch.DmaActive = false; ch.DmaActive = false;
@ -131,12 +153,14 @@ bool DmaController::InitHdmaChannels()
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
ch.HdmaTableAddress++; ch.HdmaTableAddress++;
if(ch.HdmaLineCounterAndRepeat == 0) { if (ch.HdmaLineCounterAndRepeat == 0)
{
ch.HdmaFinished = true; ch.HdmaFinished = true;
} }
//3. Load Indirect Address, if necessary. //3. Load Indirect Address, if necessary.
if(ch.HdmaIndirectAddressing) { if (ch.HdmaIndirectAddressing)
{
uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
@ -146,7 +170,8 @@ bool DmaController::InitHdmaChannels()
} }
} }
if(needSync) { if (needSync)
{
SyncEndDma(); SyncEndDma();
} }
@ -154,15 +179,17 @@ bool DmaController::InitHdmaChannels()
return true; 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]; uint8_t transferByteCount = _transferByteCount[channel.TransferMode];
channel.DmaActive = false; channel.DmaActive = false;
uint8_t i = 0; uint8_t i = 0;
if(channel.HdmaIndirectAddressing) { if (channel.HdmaIndirectAddressing)
do { {
do
{
CopyDmaByte( CopyDmaByte(
(channel.HdmaBank << 16) | channel.TransferSize, (channel.HdmaBank << 16) | channel.TransferSize,
0x2100 | (channel.DestAddress + transferOffsets[i]), 0x2100 | (channel.DestAddress + transferOffsets[i]),
@ -170,9 +197,13 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
); );
channel.TransferSize++; channel.TransferSize++;
i++; i++;
} while(i < transferByteCount); }
} else { while (i < transferByteCount);
do { }
else
{
do
{
CopyDmaByte( CopyDmaByte(
(channel.SrcBank << 16) | channel.HdmaTableAddress, (channel.SrcBank << 16) | channel.HdmaTableAddress,
0x2100 | (channel.DestAddress + transferOffsets[i]), 0x2100 | (channel.DestAddress + transferOffsets[i]),
@ -180,7 +211,8 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
); );
channel.HdmaTableAddress++; channel.HdmaTableAddress++;
i++; 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" //"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause"
uint8_t cpuSpeed = _memoryManager->GetCpuSpeed(); uint8_t cpuSpeed = _memoryManager->GetCpuSpeed();
_memoryManager->IncrementMasterClockValue(cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed)); _memoryManager->IncrementMasterClockValue(
cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed));
} }
bool DmaController::HasActiveDmaChannel() bool DmaController::HasActiveDmaChannel()
{ {
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
if(_channel[i].DmaActive) { {
if (_channel[i].DmaActive)
{
return true; return true;
} }
} }
@ -212,13 +247,15 @@ bool DmaController::ProcessHdmaChannels()
{ {
_hdmaPending = false; _hdmaPending = false;
if(!_hdmaChannels) { if (!_hdmaChannels)
{
UpdateNeedToProcessFlag(); UpdateNeedToProcessFlag();
return false; return false;
} }
bool needSync = !HasActiveDmaChannel(); bool needSync = !HasActiveDmaChannel();
if(needSync) { if (needSync)
{
SyncStartDma(); SyncStartDma();
} }
_memoryManager->IncMasterClock8(); _memoryManager->IncMasterClock8();
@ -226,20 +263,24 @@ bool DmaController::ProcessHdmaChannels()
uint8_t originalActiveChannel = _activeChannel; uint8_t originalActiveChannel = _activeChannel;
//Run all the DMA transfers for each channel first, before fetching data for the next scanline //Run all the DMA transfers for each channel first, before fetching data for the next scanline
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
DmaChannelConfig &ch = _channel[i]; {
if((_hdmaChannels & (1 << i)) == 0) { DmaChannelConfig& ch = _channel[i];
if ((_hdmaChannels & (1 << i)) == 0)
{
continue; continue;
} }
ch.DmaActive = false; ch.DmaActive = false;
if(ch.HdmaFinished) { if (ch.HdmaFinished)
{
continue; continue;
} }
//1. If DoTransfer is false, skip to step 3. //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... //2. For the number of bytes (1, 2, or 4) required for this Transfer Mode...
_activeChannel = DmaController::HdmaChannelFlag | i; _activeChannel = DmaController::HdmaChannelFlag | i;
RunHdmaTransfer(ch); RunHdmaTransfer(ch);
@ -247,9 +288,11 @@ bool DmaController::ProcessHdmaChannels()
} }
//Update the channel's state & fetch data for the next scanline //Update the channel's state & fetch data for the next scanline
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
DmaChannelConfig &ch = _channel[i]; {
if((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished) { DmaChannelConfig& ch = _channel[i];
if ((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished)
{
continue; continue;
} }
@ -265,32 +308,38 @@ bool DmaController::ProcessHdmaChannels()
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
//5. If Line Counter is zero... //5. If Line Counter is zero...
if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) { if ((ch.HdmaLineCounterAndRepeat & 0x7F) == 0)
{
ch.HdmaLineCounterAndRepeat = newCounter; ch.HdmaLineCounterAndRepeat = newCounter;
ch.HdmaTableAddress++; ch.HdmaTableAddress++;
//"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)." //"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.HdmaIndirectAddressing)
if(ch.HdmaLineCounterAndRepeat == 0 && IsLastActiveHdmaChannel(i)) { {
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, //"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." //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); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
ch.TransferSize = (msb << 8); ch.TransferSize = (msb << 8);
} else { }
else
{
//"If a new indirect address is required, 16 master cycles are taken to load it." //"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); uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
_memoryManager->IncMasterClock4(); _memoryManager->IncMasterClock4();
ch.TransferSize = (msb << 8) | lsb; 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." //"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; ch.HdmaFinished = true;
} }
@ -299,7 +348,8 @@ bool DmaController::ProcessHdmaChannels()
} }
} }
if(needSync) { if (needSync)
{
//If we ran a HDMA transfer, sync //If we ran a HDMA transfer, sync
SyncEndDma(); SyncEndDma();
} }
@ -312,8 +362,10 @@ bool DmaController::ProcessHdmaChannels()
bool DmaController::IsLastActiveHdmaChannel(uint8_t channel) bool DmaController::IsLastActiveHdmaChannel(uint8_t channel)
{ {
for(int i = channel + 1; i < 8; i++) { for (int i = channel + 1; i < 8; i++)
if((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished) { {
if ((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished)
{
return false; return false;
} }
} }
@ -328,7 +380,8 @@ void DmaController::UpdateNeedToProcessFlag()
void DmaController::BeginHdmaTransfer() void DmaController::BeginHdmaTransfer()
{ {
if(_hdmaChannels) { if (_hdmaChannels)
{
_hdmaPending = true; _hdmaPending = true;
UpdateNeedToProcessFlag(); UpdateNeedToProcessFlag();
} }
@ -342,33 +395,42 @@ void DmaController::BeginHdmaInit()
bool DmaController::ProcessPendingTransfers() bool DmaController::ProcessPendingTransfers()
{ {
if(!_needToProcess) { if (!_needToProcess)
{
return false; return false;
} }
if(_dmaStartDelay) { if (_dmaStartDelay)
{
_dmaStartDelay = false; _dmaStartDelay = false;
return false; return false;
} }
if(_hdmaPending) { if (_hdmaPending)
{
return ProcessHdmaChannels(); return ProcessHdmaChannels();
} else if(_hdmaInitPending) { }
else if (_hdmaInitPending)
{
return InitHdmaChannels(); return InitHdmaChannels();
} else if(_dmaPending) { }
else if (_dmaPending)
{
_dmaPending = false; _dmaPending = false;
SyncStartDma(); SyncStartDma();
_memoryManager->IncMasterClock8(); _memoryManager->IncMasterClock8();
ProcessPendingTransfers(); ProcessPendingTransfers();
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
if(_channel[i].DmaActive) { {
if (_channel[i].DmaActive)
{
_activeChannel = i; _activeChannel = i;
RunDma(_channel[i]); RunDma(_channel[i]);
} }
} }
SyncEndDma(); SyncEndDma();
UpdateNeedToProcessFlag(); UpdateNeedToProcessFlag();
@ -380,16 +442,21 @@ bool DmaController::ProcessPendingTransfers()
void DmaController::Write(uint16_t addr, uint8_t value) void DmaController::Write(uint16_t addr, uint8_t value)
{ {
switch(addr) { switch (addr)
case 0x420B: { {
case 0x420B:
{
//MDMAEN - DMA Enable //MDMAEN - DMA Enable
for(int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
if(value & (1 << i)) { {
if (value & (1 << i))
{
_channel[i].DmaActive = true; _channel[i].DmaActive = true;
} }
} }
if(value) { if (value)
{
_dmaPending = true; _dmaPending = true;
_dmaStartDelay = true; _dmaStartDelay = true;
UpdateNeedToProcessFlag(); UpdateNeedToProcessFlag();
@ -397,15 +464,22 @@ void DmaController::Write(uint16_t addr, uint8_t value)
break; break;
} }
case 0x420C: case 0x420C:
//HDMAEN - HDMA Enable //HDMAEN - HDMA Enable
_hdmaChannels = value; _hdmaChannels = value;
break; 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 //DMAPx - DMA Control for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.InvertDirection = (value & 0x80) != 0; channel.InvertDirection = (value & 0x80) != 0;
channel.HdmaIndirectAddressing = (value & 0x40) != 0; channel.HdmaIndirectAddressing = (value & 0x40) != 0;
channel.UnusedFlag = (value & 0x20) != 0; channel.UnusedFlag = (value & 0x20) != 0;
@ -415,101 +489,192 @@ void DmaController::Write(uint16_t addr, uint8_t value)
break; 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 //BBADx - DMA Destination Register for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.DestAddress = value; channel.DestAddress = value;
break; 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; channel.SrcAddress = (channel.SrcAddress & 0xFF00) | value;
break; 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); channel.SrcAddress = (channel.SrcAddress & 0xFF) | (value << 8);
break; 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; channel.SrcBank = value;
break; 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) //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; channel.TransferSize = (channel.TransferSize & 0xFF00) | value;
break; 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) //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); channel.TransferSize = (channel.TransferSize & 0xFF) | (value << 8);
break; 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) //DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.HdmaBank = value; channel.HdmaBank = value;
break; 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) //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; channel.HdmaTableAddress = (channel.HdmaTableAddress & 0xFF00) | value;
break; 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) //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); channel.HdmaTableAddress = (value << 8) | (channel.HdmaTableAddress & 0xFF);
break; 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) //DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.HdmaLineCounterAndRepeat = value; channel.HdmaLineCounterAndRepeat = value;
break; break;
} }
case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B: case 0x430B:
case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F: 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) //UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
channel.UnusedByte = value; channel.UnusedByte = value;
} }
} }
} }
uint8_t DmaController::Read(uint16_t addr) uint8_t DmaController::Read(uint16_t addr)
{ {
switch(addr) { switch (addr)
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 //DMAPx - DMA Control for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return ( return (
(channel.InvertDirection ? 0x80 : 0) | (channel.InvertDirection ? 0x80 : 0) |
(channel.HdmaIndirectAddressing ? 0x40 : 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 //BBADx - DMA Destination Register for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return channel.DestAddress; 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; 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; 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; 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) //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; 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) //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; 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) //DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return channel.HdmaBank; 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) //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; 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) //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; 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) //DASBx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return channel.HdmaLineCounterAndRepeat; return channel.HdmaLineCounterAndRepeat;
} }
case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B: case 0x430B:
case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F: 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) //UNUSEDx - HDMA Indirect Address bank byte (x=0-7)
DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4];
return channel.UnusedByte; return channel.UnusedByte;
} }
} }
return _memoryManager->GetOpenBus(); return _memoryManager->GetOpenBus();
} }
@ -609,10 +857,11 @@ DmaChannelConfig DmaController::GetChannelConfig(uint8_t channel)
return _channel[channel]; return _channel[channel];
} }
void DmaController::Serialize(Serializer &s) void DmaController::Serialize(Serializer& s)
{ {
s.Stream(_hdmaPending, _hdmaChannels, _dmaPending, _dmaStartClock, _hdmaInitPending, _dmaStartDelay, _needToProcess); 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( s.Stream(
_channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer, _channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer,
_channel[i].HdmaBank, _channel[i].HdmaFinished, _channel[i].HdmaIndirectAddressing, _channel[i].HdmaBank, _channel[i].HdmaFinished, _channel[i].HdmaIndirectAddressing,

View file

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

View file

@ -26,4 +26,4 @@ struct DmaChannelConfig
bool UnusedFlag; bool UnusedFlag;
uint8_t UnusedByte; // 43xB and 43xF uint8_t UnusedByte; // 43xB and 43xF
}; };

View file

@ -18,34 +18,50 @@ protected:
int _yScale; int _yScale;
virtual void InternalDraw() = 0; virtual void InternalDraw() = 0;
__forceinline void DrawPixel(uint32_t x, uint32_t y, int color) __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 //Out of bounds, skip drawing
return; return;
} }
uint32_t alpha = (color & 0xFF000000); uint32_t alpha = (color & 0xFF000000);
if(alpha > 0) { if (alpha > 0)
if(_yScale == 1) { {
if(alpha != 0xFF000000) { if (_yScale == 1)
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)], (uint8_t*)&color); {
} else { if (alpha != 0xFF000000)
_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)] = color; {
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)],
(uint8_t*)&color);
} }
} else { else
int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1)*_xScale) - (int)(x*_xScale); {
_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)); x = (int)(x * (_useIntegerScaling ? _yScale : _xScale));
y = (int)(y * _yScale); y = (int)(y * _yScale);
int top = (int)(_overscan.Top * _yScale); int top = (int)(_overscan.Top * _yScale);
int left = (int)(_overscan.Left * _xScale); int left = (int)(_overscan.Left * _xScale);
for(int i = 0; i < _yScale; i++) { for (int i = 0; i < _yScale; i++)
for(int j = 0; j < xPixelCount; j++) { {
if(alpha != 0xFF000000) { for (int j = 0; j < xPixelCount; j++)
BlendColors((uint8_t*)&_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left)+j], (uint8_t*)&color); {
} else { if (alpha != 0xFF000000)
_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left) +j] = color; {
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: public:
DrawCommand(int startFrame, int frameCount, bool useIntegerScaling = false) DrawCommand(int startFrame, int frameCount, bool useIntegerScaling = false)
{ {
_frameCount = frameCount > 0 ? frameCount : -1; _frameCount = frameCount > 0 ? frameCount : -1;
_startFrame = startFrame; _startFrame = startFrame;
_useIntegerScaling = useIntegerScaling; _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; _argbBuffer = argbBuffer;
_overscan = overscan; _overscan = overscan;
_lineWidth = lineWidth; _lineWidth = lineWidth;

View file

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

View file

@ -11,18 +11,25 @@ private:
protected: protected:
void InternalDraw() void InternalDraw()
{ {
if(_fill) { if (_fill)
for(int j = 0; j < _height; j++) { {
for(int i = 0; i < _width; i++) { for (int j = 0; j < _height; j++)
{
for (int i = 0; i < _width; i++)
{
DrawPixel(_x + i, _y + j, _color); 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, _color);
DrawPixel(_x + i, _y + _height - 1, _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, _y + i, _color);
DrawPixel(_x + _width - 1, _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) : 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) DrawCommand(startFrame, frameCount), _x(x), _y(y), _width(width), _height(height), _color(color), _fill(fill)
{ {
if(width < 0) { if (width < 0)
{
_x += width + 1; _x += width + 1;
_width = -width; _width = -width;
} }
if(height < 0) { if (height < 0)
{
_y += height + 1; _y += height + 1;
_height = -height; _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) //Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time)
_color = (~color & 0xFF000000) | (color & 0xFFFFFF); _color = (~color & 0xFF000000) | (color & 0xFFFFFF);
} }
}; };

View file

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

View file

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

View file

@ -16,7 +16,9 @@
DummyCpu::DummyCpu(Console* console, CpuType type) DummyCpu::DummyCpu(Console* console, CpuType type)
{ {
_console = console; _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; _dmaController = nullptr;
_memoryManager = nullptr; _memoryManager = nullptr;
} }
@ -33,7 +35,7 @@ void DummyCpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
LogWrite(addr, value); LogWrite(addr, value);
} }
void DummyCpu::SetDummyState(CpuState &state) void DummyCpu::SetDummyState(CpuState& state)
{ {
_state = state; _state = state;
_state.StopState = CpuStopState::Running; _state.StopState = CpuStopState::Running;
@ -65,13 +67,13 @@ void DummyCpu::LogWrite(uint32_t addr, uint8_t value)
_writeCounter++; _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]; addr = _writeAddresses[index];
value = _writeValue[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]; addr = _readAddresses[index];
value = _readValue[index]; value = _readValue[index];
@ -80,4 +82,4 @@ void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value)
int32_t DummyCpu::GetLastOperand() int32_t DummyCpu::GetLastOperand()
{ {
return _operand; return _operand;
} }

View file

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

View file

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

View file

@ -31,7 +31,7 @@ private:
std::unordered_map<uint32_t, KeyCombination> _emulatorKeys[3]; std::unordered_map<uint32_t, KeyCombination> _emulatorKeys[3];
std::unordered_map<uint32_t, vector<KeyCombination>> _shortcutSupersets[3]; std::unordered_map<uint32_t, vector<KeyCombination>> _shortcutSupersets[3];
void ProcessString(string &str, const char** strPointer); void ProcessString(string& str, const char** strPointer);
void ClearShortcutKeys(); void ClearShortcutKeys();
void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex); void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex);
@ -77,11 +77,11 @@ public:
void SetDebuggerFlag(DebuggerFlags flag, bool enabled); void SetDebuggerFlag(DebuggerFlags flag, bool enabled);
bool CheckDebuggerFlag(DebuggerFlags flags); bool CheckDebuggerFlag(DebuggerFlags flags);
int GetRandomValue(int maxValue); int GetRandomValue(int maxValue);
bool GetRandomBool(); bool GetRandomBool();
void InitializeRam(void* data, uint32_t length); void InitializeRam(void* data, uint32_t length);
bool IsInputEnabled(); bool IsInputEnabled();
double GetControllerDeadzoneRatio(); double GetControllerDeadzoneRatio();
}; };

View file

@ -10,7 +10,8 @@
#include "DefaultVideoFilter.h" #include "DefaultVideoFilter.h"
#include "BaseEventManager.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; _debugger = debugger;
_cpu = cpu; _cpu = cpu;
@ -27,7 +28,7 @@ EventManager::~EventManager()
delete[] _ppuBuffer; delete[] _ppuBuffer;
} }
void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo &operation, int32_t breakpointId) void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId)
{ {
DebugEventInfo evt = {}; DebugEventInfo evt = {};
evt.Type = type; evt.Type = type;
@ -36,10 +37,13 @@ void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo &operation,
evt.Cycle = _memoryManager->GetHClock(); evt.Cycle = _memoryManager->GetHClock();
evt.BreakpointId = breakpointId; 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.DmaChannel = _dmaController->GetActiveChannel();
evt.DmaChannelInfo = _dmaController->GetChannelConfig(evt.DmaChannel & 0x07); evt.DmaChannelInfo = _dmaController->GetChannelConfig(evt.DmaChannel & 0x07);
} else { }
else
{
evt.DmaChannel = -1; evt.DmaChannel = -1;
} }
@ -57,14 +61,14 @@ void EventManager::AddEvent(DebugEventType type)
evt.Cycle = _memoryManager->GetHClock(); evt.Cycle = _memoryManager->GetHClock();
evt.BreakpointId = -1; evt.BreakpointId = -1;
evt.DmaChannel = -1; evt.DmaChannel = -1;
CpuState state = _cpu->GetState(); CpuState state = _cpu->GetState();
evt.ProgramCounter = (state.K << 16) | state.PC; evt.ProgramCounter = (state.K << 16) | state.PC;
_debugEvents.push_back(evt); _debugEvents.push_back(evt);
} }
void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount) void EventManager::GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount)
{ {
auto lock = _lock.AcquireSafe(); auto lock = _lock.AcquireSafe();
uint32_t eventCount = std::min(maxEventCount, (uint32_t)_sentEvents.size()); uint32_t eventCount = std::min(maxEventCount, (uint32_t)_sentEvents.size());
@ -72,12 +76,14 @@ void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount
maxEventCount = eventCount; 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(); auto lock = _lock.AcquireSafe();
for(DebugEventInfo &evt : _sentEvents) { for (DebugEventInfo& evt : _sentEvents)
if(evt.Cycle == cycle && evt.Scanline == scanline) { {
if (evt.Cycle == cycle && evt.Scanline == scanline)
{
return evt; return evt;
} }
} }
@ -100,120 +106,191 @@ void EventManager::ClearFrameEvents()
_debugEvents.clear(); _debugEvents.clear();
} }
void EventManager::FilterEvents(EventViewerDisplayOptions &options) void EventManager::FilterEvents(EventViewerDisplayOptions& options)
{ {
auto lock = _lock.AcquireSafe(); auto lock = _lock.AcquireSafe();
_sentEvents.clear(); _sentEvents.clear();
vector<DebugEventInfo> events = _snapshot; vector<DebugEventInfo> events = _snapshot;
if(options.ShowPreviousFrameEvents && _snapshotScanline != 0) { if (options.ShowPreviousFrameEvents && _snapshotScanline != 0)
{
uint32_t key = (_snapshotScanline << 16) + _snapshotCycle; uint32_t key = (_snapshotScanline << 16) + _snapshotCycle;
for(DebugEventInfo &evt : _prevDebugEvents) { for (DebugEventInfo& evt : _prevDebugEvents)
{
uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle; uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle;
if(evtKey > key) { if (evtKey > key)
{
events.push_back(evt); events.push_back(evt);
} }
} }
} }
for(DebugEventInfo &evt : events) { 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 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; bool showEvent = false;
switch(evt.Type) { switch (evt.Type)
case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints;break; {
case DebugEventType::Irq: showEvent = options.ShowIrq; break; case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints;
case DebugEventType::Nmi: showEvent = options.ShowNmi; break; break;
case DebugEventType::Register: case DebugEventType::Irq: showEvent = options.ShowIrq;
if(isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07]) { break;
showEvent = false; case DebugEventType::Nmi: showEvent = options.ShowNmi;
break; break;
} case DebugEventType::Register:
if (isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07])
uint16_t reg = evt.Operation.Address & 0xFFFF; {
if(reg <= 0x213F) { showEvent = false;
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; 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); _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; uint32_t color = 0;
switch(evt.Type) { switch (evt.Type)
case DebugEventType::Breakpoint: color = options.BreakpointColor; break; {
case DebugEventType::Irq: color = options.IrqColor; break; case DebugEventType::Breakpoint: color = options.BreakpointColor;
case DebugEventType::Nmi: color = options.NmiColor; break; break;
case DebugEventType::Register: case DebugEventType::Irq: color = options.IrqColor;
uint16_t reg = evt.Operation.Address & 0xFFFF; break;
if(reg <= 0x213F) { case DebugEventType::Nmi: color = options.NmiColor;
if(isWrite) { break;
if(reg >= 0x2101 && reg <= 0x2104) { case DebugEventType::Register:
color = options.PpuRegisterWriteOamColor; uint16_t reg = evt.Operation.Address & 0xFFFF;
} else if(reg >= 0x2105 && reg <= 0x210C) { if (reg <= 0x213F)
color = options.PpuRegisterWriteBgOptionColor; {
} else if(reg >= 0x210D && reg <= 0x2114) { if (isWrite)
color = options.PpuRegisterWriteBgScrollColor; {
} else if(reg >= 0x2115 && reg <= 0x2119) { if (reg >= 0x2101 && reg <= 0x2104)
color = options.PpuRegisterWriteVramColor; {
} else if(reg >= 0x211A && reg <= 0x2120) { color = options.PpuRegisterWriteOamColor;
color = options.PpuRegisterWriteMode7Color; }
} else if(reg >= 0x2121 && reg <= 0x2122) { else if (reg >= 0x2105 && reg <= 0x210C)
color = options.PpuRegisterWriteCgramColor; {
} else if(reg >= 0x2123 && reg <= 0x212B) { color = options.PpuRegisterWriteBgOptionColor;
color = options.PpuRegisterWriteWindowColor; }
} else { else if (reg >= 0x210D && reg <= 0x2114)
color = options.PpuRegisterWriteOtherColor; {
} color = options.PpuRegisterWriteBgScrollColor;
} else { }
color = options.PpuRegisterReadColor; 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); color = 0xFF000000 | ((color >> 1) & 0x7F7F7F);
} else { }
else
{
color |= 0xFF000000; color |= 0xFF000000;
} }
@ -224,10 +301,13 @@ void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t
uint32_t y = std::min<uint32_t>(evt.Scanline * 2, _scanlineCount * 2); uint32_t y = std::min<uint32_t>(evt.Scanline * 2, _scanlineCount * 2);
uint32_t x = evt.Cycle / 2; uint32_t x = evt.Cycle / 2;
for(int i = iMin; i <= iMax; i++) { for (int i = iMin; i <= iMax; i++)
for(int j = jMin; j <= jMax; j++) { {
for (int j = jMin; j <= jMax; j++)
{
int32_t pos = (y + i) * EventManager::ScanlineWidth + x + 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; continue;
} }
buffer[pos] = color; buffer[pos] = color;
@ -247,14 +327,17 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
_overscanMode = _ppu->GetState().OverscanMode; _overscanMode = _ppu->GetState().OverscanMode;
_useHighResOutput = _ppu->IsHighResOutput(); _useHighResOutput = _ppu->IsHighResOutput();
if(scanline >= _ppu->GetNmiScanline() || scanline == 0) { if (scanline >= _ppu->GetNmiScanline() || scanline == 0)
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256*239)) * sizeof(uint16_t)); {
} else { memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256 * 239)) * sizeof(uint16_t));
}
else
{
uint16_t adjustedScanline = scanline + (_overscanMode ? 0 : 7); uint16_t adjustedScanline = scanline + (_overscanMode ? 0 : 7);
uint32_t size = _useHighResOutput ? (512 * 478) : (256 * 239); uint32_t size = _useHighResOutput ? (512 * 478) : (256 * 239);
uint32_t offset = _useHighResOutput ? (512 * adjustedScanline * 2) : (256 * adjustedScanline); uint32_t offset = _useHighResOutput ? (512 * adjustedScanline * 2) : (256 * adjustedScanline);
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), offset * sizeof(uint16_t)); 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; _snapshot = _debugEvents;
@ -264,25 +347,29 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
return _scanlineCount; 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(); auto lock = _lock.AcquireSafe();
if(_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4) { if (_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4)
{
return; 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; buffer[i] = 0xFF555555;
} }
//Skip the first 7 blank lines in the buffer when overscan mode is off //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 y = 0, len = _overscanMode ? 239 * 2 : 224 * 2; y < len; y++)
for(uint32_t x = 0; x < 512; x++) { {
for (uint32_t x = 0; x < 512; x++)
{
int srcOffset = _useHighResOutput ? ((y << 9) | x) : (((y >> 1) << 8) | (x >> 1)); 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; constexpr uint32_t currentScanlineColor = 0xFFFFFF55;
int nmiScanline = (_overscanMode ? 240 : 225) * 2 * EventManager::ScanlineWidth; int nmiScanline = (_overscanMode ? 240 : 225) * 2 * EventManager::ScanlineWidth;
uint32_t scanlineOffset = _snapshotScanline * 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 + i] = nmiColor;
buffer[nmiScanline + EventManager::ScanlineWidth + i] = nmiColor; buffer[nmiScanline + EventManager::ScanlineWidth + i] = nmiColor;
if(_snapshotScanline != 0) { if (_snapshotScanline != 0)
{
buffer[scanlineOffset + i] = currentScanlineColor; buffer[scanlineOffset + i] = currentScanlineColor;
buffer[scanlineOffset + EventManager::ScanlineWidth + i] = currentScanlineColor; buffer[scanlineOffset + EventManager::ScanlineWidth + i] = currentScanlineColor;
} }
} }
FilterEvents(options); FilterEvents(options);
for(DebugEventInfo &evt : _sentEvents) { for (DebugEventInfo& evt : _sentEvents)
{
DrawEvent(evt, true, buffer, options); DrawEvent(evt, true, buffer, options);
} }
for(DebugEventInfo &evt : _sentEvents) { for (DebugEventInfo& evt : _sentEvents)
{
DrawEvent(evt, false, buffer, options); DrawEvent(evt, false, buffer, options);
} }
} }

View file

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

View file

@ -14,4 +14,4 @@ enum class EventType
GbStartFrame, GbStartFrame,
GbEndFrame, GbEndFrame,
EventTypeSize EventTypeSize
}; };

File diff suppressed because it is too large Load diff

View file

@ -39,8 +39,10 @@ enum EvalOperators : int64_t
LogicalNot = 20000000053, LogicalNot = 20000000053,
//Used to read ram address //Used to read ram address
Bracket = 20000000054, //Read byte Bracket = 20000000054,
Braces = 20000000055, //Read word //Read byte
Braces = 20000000055,
//Read word
//Special value, not used as an operator //Special value, not used as an operator
Parenthesis = 20000000100, Parenthesis = 20000000100,
@ -133,7 +135,7 @@ enum class EvalResultType : int32_t
class StringHasher class StringHasher
{ {
public: 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. //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(); return t.size();
@ -157,36 +159,40 @@ private:
std::unordered_map<string, ExpressionData, StringHasher> _cache; std::unordered_map<string, ExpressionData, StringHasher> _cache;
SimpleLock _cacheLock; SimpleLock _cacheLock;
int64_t operandStack[1000]; int64_t operandStack[1000];
Debugger* _debugger; Debugger* _debugger;
LabelManager* _labelManager; LabelManager* _labelManager;
CpuType _cpuType; CpuType _cpuType;
SnesMemoryType _cpuMemory; SnesMemoryType _cpuMemory;
bool IsOperator(string token, int &precedence, bool unaryOperator); bool IsOperator(string token, int& precedence, bool unaryOperator);
EvalOperators GetOperator(string token, 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 ProcessCpuSpcTokens(string token, bool spc);
int64_t ProcessSharedTokens(string token); int64_t ProcessSharedTokens(string token);
int64_t ProcessGsuTokens(string token); int64_t ProcessGsuTokens(string token);
int64_t ProcessGameboyTokens(string token); int64_t ProcessGameboyTokens(string token);
string GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp); string GetNextToken(string expression, size_t& pos, ExpressionData& data, bool& success, bool previousTokenIsOp);
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int64_t> &outputQueue); bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators>& opStack,
bool ToRpn(string expression, ExpressionData &data); std::stack<int>& precedenceStack, vector<int64_t>& outputQueue);
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo, bool &success); 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); ExpressionData* PrivateGetRpnList(string expression, bool& success);
public: public:
ExpressionEvaluator(Debugger* debugger, CpuType cpuType); ExpressionEvaluator(Debugger* debugger, CpuType cpuType);
int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo); int32_t Evaluate(ExpressionData& data, DebugState& state, EvalResultType& resultType,
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo); MemoryOperationInfo& operationInfo);
ExpressionData GetRpnList(string expression, bool &success); int32_t Evaluate(string expression, DebugState& state, EvalResultType& resultType,
MemoryOperationInfo& operationInfo);
ExpressionData GetRpnList(string expression, bool& success);
bool Validate(string expression); bool Validate(string expression);
#if _DEBUG #if _DEBUG
void RunTests(); void RunTests();
#endif #endif
}; };

View file

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

View file

@ -11,13 +11,15 @@ private:
string _disconnectMessage; string _disconnectMessage;
protected: protected:
void Serialize(Serializer &s) override void Serialize(Serializer& s) override
{ {
s.Stream(_disconnectMessage); s.Stream(_disconnectMessage);
} }
public: 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) ForceDisconnectMessage(string message) : NetMessage(MessageType::ForceDisconnect)
{ {
@ -28,4 +30,4 @@ public:
{ {
return _disconnectMessage; return _disconnectMessage;
} }
}; };

View file

@ -25,7 +25,8 @@ public:
void ProcessFrame() void ProcessFrame()
{ {
if(_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300) { if (_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300)
{
//Reset the timers, this can happen in 3 scenarios: //Reset the timers, this can happen in 3 scenarios:
//1) Target frame rate changed //1) Target frame rate changed
//2) The console was reset/power cycled or the emulation was paused (with or without the debugger) //2) The console was reset/power cycled or the emulation was paused (with or without the debugger)
@ -41,7 +42,8 @@ public:
bool WaitForNextFrame() 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 //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); _clockTimer.WaitUntil(_clockTimer.GetElapsedMS() + 40);
return true; return true;
@ -50,4 +52,4 @@ public:
_clockTimer.WaitUntil(_targetTime); _clockTimer.WaitUntil(_targetTime);
return false; return false;
} }
}; };

View file

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

View file

@ -23,7 +23,7 @@ private:
static shared_ptr<GameClientConnection> GetConnection(); static shared_ptr<GameClientConnection> GetConnection();
void PrivateConnect(ClientConnectionData &connectionData); void PrivateConnect(ClientConnectionData& connectionData);
void Exec(); void Exec();
public: public:
@ -31,7 +31,7 @@ public:
virtual ~GameClient(); virtual ~GameClient();
static bool Connected(); static bool Connected();
static void Connect(shared_ptr<Console> console, ClientConnectionData &connectionData); static void Connect(shared_ptr<Console> console, ClientConnectionData& connectionData);
static void Disconnect(); static void Disconnect();
static void SelectController(uint8_t port); static void SelectController(uint8_t port);
@ -39,4 +39,4 @@ public:
static uint8_t GetAvailableControllers(); static uint8_t GetAvailableControllers();
void ProcessNotification(ConsoleNotificationType type, void* parameter) override; void ProcessNotification(ConsoleNotificationType type, void* parameter) override;
}; };

View file

@ -17,7 +17,8 @@
#include "NotificationManager.h" #include "NotificationManager.h"
#include "RomFinder.h" #include "RomFinder.h"
GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData &connectionData) : GameConnection(console, socket) GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket,
ClientConnectionData& connectionData) : GameConnection(console, socket)
{ {
_connectionData = connectionData; _connectionData = connectionData;
_shutdown = false; _shutdown = false;
@ -34,12 +35,14 @@ GameClientConnection::~GameClientConnection()
void GameClientConnection::Shutdown() void GameClientConnection::Shutdown()
{ {
if(!_shutdown) { if (!_shutdown)
{
_shutdown = true; _shutdown = true;
DisableControllers(); DisableControllers();
shared_ptr<ControlManager> controlManager = _console->GetControlManager(); shared_ptr<ControlManager> controlManager = _console->GetControlManager();
if(controlManager) { if (controlManager)
{
controlManager->UnregisterInputProvider(this); controlManager->UnregisterInputProvider(this);
} }
@ -50,7 +53,9 @@ void GameClientConnection::Shutdown()
void GameClientConnection::SendHandshake() 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); SendNetMessage(message);
} }
@ -63,7 +68,8 @@ void GameClientConnection::SendControllerSelection(uint8_t port)
void GameClientConnection::ClearInputData() void GameClientConnection::ClearInputData()
{ {
LockHandler lock = _writeLock.AcquireSafe(); LockHandler lock = _writeLock.AcquireSafe();
for(int i = 0; i < BaseControlDevice::PortCount; i++) { for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
_inputSize[i] = 0; _inputSize[i] = 0;
_inputData[i].clear(); _inputData[i].clear();
} }
@ -73,80 +79,98 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
{ {
GameInformationMessage* gameInfo; GameInformationMessage* gameInfo;
switch(message->GetType()) { switch (message->GetType())
case MessageType::ServerInformation: {
_serverSalt = ((ServerInformationMessage*)message)->GetHashSalt(); case MessageType::ServerInformation:
SendHandshake(); _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt();
break; SendHandshake();
break;
case MessageType::SaveState: case MessageType::SaveState:
if(_gameLoaded) { 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:
DisableControllers(); DisableControllers();
_console->Lock(); _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(); ClearInputData();
((SaveStateMessage*)message)->LoadState(_console);
_enableControllers = true;
InitControlDevice();
_console->Unlock(); _console->Unlock();
}
break;
_gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash()); case MessageType::MovieData:
if(!_gameLoaded) { if (_gameLoaded)
_console->Stop(true); {
} else { PushControllerState(((MovieDataMessage*)message)->GetPortNumber(),
_console->GetControlManager()->UnregisterInputProvider(this); ((MovieDataMessage*)message)->GetInputState());
_console->GetControlManager()->RegisterInputProvider(this); }
if(gameInfo->IsPaused()) { break;
_console->Pause();
} else { case MessageType::ForceDisconnect:
_console->Resume(); 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; else
default: {
break; 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) bool GameClientConnection::AttemptLoadGame(string filename, string sha1Hash)
{ {
if(filename.size() > 0) { if (filename.size() > 0)
if(!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash)) { {
if (!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash))
{
MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom", filename); MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom", filename);
return false; return false;
} else { }
else
{
return true; return true;
} }
} }
@ -159,7 +183,8 @@ void GameClientConnection::PushControllerState(uint8_t port, ControlDeviceState
_inputData[port].push_back(state); _inputData[port].push_back(state);
_inputSize[port]++; _inputSize[port]++;
if(_inputData[port].size() >= _minimumQueueSize) { if (_inputData[port].size() >= _minimumQueueSize)
{
_waitForInput[port].Signal(); _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()) //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; _enableControllers = false;
ClearInputData(); ClearInputData();
for(int i = 0; i < BaseControlDevice::PortCount; i++) { for (int i = 0; i < BaseControlDevice::PortCount; i++)
{
_waitForInput[i].Signal(); _waitForInput[i].Signal();
} }
} }
bool GameClientConnection::SetInput(BaseControlDevice *device) bool GameClientConnection::SetInput(BaseControlDevice* device)
{ {
if(_enableControllers) { if (_enableControllers)
{
uint8_t port = device->GetPort(); uint8_t port = device->GetPort();
while(_inputSize[port] == 0) { while (_inputSize[port] == 0)
{
_waitForInput[port].Wait(); _waitForInput[port].Wait();
if(port == 0 && _minimumQueueSize < 10) { if (port == 0 && _minimumQueueSize < 10)
{
//Increase buffer size - reduces freezes at the cost of additional lag //Increase buffer size - reduces freezes at the cost of additional lag
_minimumQueueSize++; _minimumQueueSize++;
} }
if(_shutdown || !_enableControllers) { if (_shutdown || !_enableControllers)
{
return true; return true;
} }
} }
LockHandler lock = _writeLock.AcquireSafe(); LockHandler lock = _writeLock.AcquireSafe();
if(_shutdown || !_enableControllers || _inputSize[port] == 0) { if (_shutdown || !_enableControllers || _inputSize[port] == 0)
{
return true; return true;
} }
@ -200,10 +231,13 @@ bool GameClientConnection::SetInput(BaseControlDevice *device)
_inputData[port].pop_front(); _inputData[port].pop_front();
_inputSize[port]--; _inputSize[port]--;
if(_inputData[port].size() > _minimumQueueSize) { if (_inputData[port].size() > _minimumQueueSize)
{
//Too much data, catch up //Too much data, catch up
_console->GetSettings()->SetFlag(EmulationFlags::MaximumSpeed); _console->GetSettings()->SetFlag(EmulationFlags::MaximumSpeed);
} else { }
else
{
_console->GetSettings()->ClearFlag(EmulationFlags::MaximumSpeed); _console->GetSettings()->ClearFlag(EmulationFlags::MaximumSpeed);
} }
@ -215,33 +249,41 @@ bool GameClientConnection::SetInput(BaseControlDevice *device)
void GameClientConnection::InitControlDevice() void GameClientConnection::InitControlDevice()
{ {
//Pretend we are using port 0 (to use player 1's keybindings during netplay) //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) void GameClientConnection::ProcessNotification(ConsoleNotificationType type, void* parameter)
{ {
if(type == ConsoleNotificationType::ConfigChanged) { if (type == ConsoleNotificationType::ConfigChanged)
{
InitControlDevice(); InitControlDevice();
} else if(type == ConsoleNotificationType::GameLoaded) { }
else if (type == ConsoleNotificationType::GameLoaded)
{
_console->GetControlManager()->RegisterInputProvider(this); _console->GetControlManager()->RegisterInputProvider(this);
} }
} }
void GameClientConnection::SendInput() void GameClientConnection::SendInput()
{ {
if(_gameLoaded) { if (_gameLoaded)
if(_newControlDevice) { {
if (_newControlDevice)
{
_controlDevice = _newControlDevice; _controlDevice = _newControlDevice;
_newControlDevice.reset(); _newControlDevice.reset();
} }
ControlDeviceState inputState; ControlDeviceState inputState;
if(_controlDevice) { if (_controlDevice)
{
_controlDevice->SetStateFromInput(); _controlDevice->SetStateFromInput();
inputState = _controlDevice->GetRawState(); inputState = _controlDevice->GetRawState();
} }
if(_lastInputSent != inputState) { if (_lastInputSent != inputState)
{
InputDataMessage message(inputState); InputDataMessage message(inputState);
SendNetMessage(message); SendNetMessage(message);
_lastInputSent = inputState; _lastInputSent = inputState;
@ -257,8 +299,10 @@ void GameClientConnection::SelectController(uint8_t port)
uint8_t GameClientConnection::GetAvailableControllers() uint8_t GameClientConnection::GetAvailableControllers()
{ {
uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1; uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1;
for(PlayerInfo &playerInfo : _playerList) { for (PlayerInfo& playerInfo : _playerList)
if(playerInfo.ControllerPort < BaseControlDevice::PortCount) { {
if (playerInfo.ControllerPort < BaseControlDevice::PortCount)
{
availablePorts &= ~(1 << playerInfo.ControllerPort); availablePorts &= ~(1 << playerInfo.ControllerPort);
} }
} }
@ -268,4 +312,4 @@ uint8_t GameClientConnection::GetAvailableControllers()
uint8_t GameClientConnection::GetControllerPort() uint8_t GameClientConnection::GetControllerPort()
{ {
return _controllerPort; return _controllerPort;
} }

View file

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

View file

@ -20,17 +20,20 @@ GameConnection::GameConnection(shared_ptr<Console> console, shared_ptr<Socket> s
void GameConnection::ReadSocket() void GameConnection::ReadSocket()
{ {
auto lock = _socketLock.AcquireSafe(); auto lock = _socketLock.AcquireSafe();
int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition, 0); int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition,
if(bytesReceived > 0) { 0);
if (bytesReceived > 0)
{
_readPosition += bytesReceived; _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); 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."); MessageManager::Log("[Netplay] Invalid data received, closing connection.");
Disconnect(); Disconnect();
return false; return false;
@ -38,8 +41,9 @@ bool GameConnection::ExtractMessage(void *buffer, uint32_t &messageLength)
int packetLength = messageLength + sizeof(messageLength); int packetLength = messageLength + sizeof(messageLength);
if(_readPosition >= packetLength) { if (_readPosition >= packetLength)
memcpy(buffer, _readBuffer+sizeof(messageLength), messageLength); {
memcpy(buffer, _readBuffer + sizeof(messageLength), messageLength);
memmove(_readBuffer, _readBuffer + packetLength, _readPosition - packetLength); memmove(_readBuffer, _readBuffer + packetLength, _readPosition - packetLength);
_readPosition -= packetLength; _readPosition -= packetLength;
return true; return true;
@ -51,26 +55,29 @@ NetMessage* GameConnection::ReadMessage()
{ {
ReadSocket(); ReadSocket();
if(_readPosition > 4) { if (_readPosition > 4)
{
uint32_t messageLength; uint32_t messageLength;
if(ExtractMessage(_messageBuffer, messageLength)) { if (ExtractMessage(_messageBuffer, messageLength))
switch((MessageType)_messageBuffer[0]) { {
case MessageType::HandShake: return new HandShakeMessage(_messageBuffer, messageLength); switch ((MessageType)_messageBuffer[0])
case MessageType::SaveState: return new SaveStateMessage(_messageBuffer, messageLength); {
case MessageType::InputData: return new InputDataMessage(_messageBuffer, messageLength); case MessageType::HandShake: return new HandShakeMessage(_messageBuffer, messageLength);
case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength); case MessageType::SaveState: return new SaveStateMessage(_messageBuffer, messageLength);
case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength); case MessageType::InputData: return new InputDataMessage(_messageBuffer, messageLength);
case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength); case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength);
case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength); case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength);
case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength); case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength);
case MessageType::ServerInformation: return new ServerInformationMessage(_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; return nullptr;
} }
void GameConnection::SendNetMessage(NetMessage &message) void GameConnection::SendNetMessage(NetMessage& message)
{ {
auto lock = _socketLock.AcquireSafe(); auto lock = _socketLock.AcquireSafe();
message.Send(*_socket.get()); message.Send(*_socket.get());
@ -90,10 +97,11 @@ bool GameConnection::ConnectionError()
void GameConnection::ProcessMessages() void GameConnection::ProcessMessages()
{ {
NetMessage* message; NetMessage* message;
while((message = ReadMessage()) != nullptr) { while ((message = ReadMessage()) != nullptr)
{
//Loop until all messages have been processed //Loop until all messages have been processed
message->Initialize(); message->Initialize();
ProcessMessage(message); ProcessMessage(message);
delete message; delete message;
} }
} }

View file

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

View file

@ -13,22 +13,25 @@ private:
bool _paused = false; bool _paused = false;
protected: protected:
void Serialize(Serializer &s) override void Serialize(Serializer& s) override
{ {
s.Stream(_romFilename, _sha1Hash, _controllerPort, _paused); s.Stream(_romFilename, _sha1Hash, _controllerPort, _paused);
} }
public: 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); _romFilename = FolderUtilities::GetFilename(filepath, true);
_sha1Hash = sha1Hash; _sha1Hash = sha1Hash;
_controllerPort = port; _controllerPort = port;
_paused = paused; _paused = paused;
} }
uint8_t GetPort() uint8_t GetPort()
{ {
return _controllerPort; return _controllerPort;
@ -48,4 +51,4 @@ public:
{ {
return _paused; return _paused;
} }
}; };

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