Revert "Merge branch 'reformat_code'"

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

View file

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

View file

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

View file

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

View file

@ -28,13 +28,9 @@ private:
bool _needSecondPass;
shared_ptr<LabelManager> _labelManager;
void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output,
std::unordered_map<string, uint32_t>& labels, bool firstPass,
std::unordered_map<string, uint32_t>& currentPassLabels);
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData,
std::unordered_map<string, uint32_t>& labels, bool firstPass);
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels,
bool firstPass);
void ProcessLine(string code, uint32_t& instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint32_t>& labels, bool firstPass, std::unordered_map<string, uint32_t>& currentPassLabels);
AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass);
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map<string, uint32_t>& labels, bool firstPass);
void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector<int16_t>& output, bool firstPass);
bool IsOpModeAvailable(string& opCode, AddrMode mode);
@ -44,4 +40,4 @@ public:
virtual ~Assembler();
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
{
private:
Console* _console;
Console *_console;
vector<unique_ptr<IMemoryHandler>> _prgRomHandlers;
vector<unique_ptr<IMemoryHandler>> _saveRamHandlers;
@ -32,12 +32,12 @@ private:
bool _needCoprocSync = false;
unique_ptr<BaseCoprocessor> _coprocessor;
NecDsp* _necDsp = nullptr;
Sa1* _sa1 = nullptr;
Gsu* _gsu = nullptr;
Cx4* _cx4 = nullptr;
SuperGameboy* _sgb = nullptr;
NecDsp *_necDsp = nullptr;
Sa1 *_sa1 = nullptr;
Gsu *_gsu = nullptr;
Cx4 *_cx4 = nullptr;
SuperGameboy *_sgb = nullptr;
BsxCart* _bsx = nullptr;
unique_ptr<BsxMemoryPack> _bsxMemPack;
unique_ptr<Gameboy> _gameboy;
@ -51,11 +51,11 @@ private:
uint8_t* _prgRom = nullptr;
uint8_t* _saveRam = nullptr;
uint32_t _prgRomSize = 0;
uint32_t _saveRamSize = 0;
uint32_t _coprocessorRamSize = 0;
shared_ptr<SpcFileData> _spcData;
vector<uint8_t> _embeddedFirmware;
@ -71,7 +71,7 @@ private:
bool MapSpecificCarts(MemoryMappings& mm);
void MapBsxMemoryPack(MemoryMappings& mm);
void ApplyConfigOverrides();
void LoadRom();
void LoadSpc();
bool LoadGameboy(VirtualFile& romFile, bool sgbEnabled);
@ -85,13 +85,13 @@ private:
public:
virtual ~BaseCartridge();
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile);
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile);
void Reset();
void SaveBattery();
void Init(MemoryMappings& mm);
void Init(MemoryMappings &mm);
RomInfo GetRomInfo();
vector<uint8_t> GetOriginalPrgRom();
@ -100,7 +100,7 @@ public:
string GetSha1Hash();
CartFlags::CartFlags GetCartFlags();
void RegisterHandlers(MemoryMappings& mm);
void RegisterHandlers(MemoryMappings &mm);
uint8_t* DebugGetPrgRom() { return _prgRom; }
uint8_t* DebugGetSaveRam() { return _saveRam; }
@ -117,11 +117,10 @@ public:
Gameboy* GetGameboy();
void RunCoprocessors();
__forceinline void SyncCoprocessors()
{
if (_needCoprocSync)
{
if(_needCoprocSync) {
_coprocessor->Run();
}
}
@ -133,5 +132,5 @@ public:
SpcFileData* GetSpcData();
void Serialize(Serializer& s) override;
void Serialize(Serializer &s) override;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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