Debugger: Added assembler tool + allow editing of existing code by using assembler (wip)
This commit is contained in:
parent
acbd7f183d
commit
09347d85b7
22 changed files with 1338 additions and 89 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -163,4 +163,6 @@ $RECYCLE.BIN/
|
|||
*.rar
|
||||
|
||||
*.VC.opendb
|
||||
*.VC.db
|
||||
*.VC.db
|
||||
*.VC.db-wal
|
||||
*.VC.db-shm
|
||||
|
|
368
Core/Assembler.cpp
Normal file
368
Core/Assembler.cpp
Normal file
|
@ -0,0 +1,368 @@
|
|||
#include "stdafx.h"
|
||||
#include <regex>
|
||||
#include <unordered_map>
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
#include "Assembler.h"
|
||||
#include "CPU.h"
|
||||
#include "DisassemblyInfo.h"
|
||||
#include "LabelManager.h"
|
||||
|
||||
static const std::regex instRegex = std::regex("^\\s*([a-z]{3})[*]{0,1}[\\s]*([#]{0,1})([(]{0,1})[\\s]*([$]{0,1})([^,)(;:]*)[\\s]*((,x\\)|\\),y|,x|,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-z][@_a-z0-9]*):(.*)", std::regex_constants::icase);
|
||||
|
||||
static string opName[256] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
"BRK", "ORA", "STP", "SLO", "NOP", "ORA", "ASL", "SLO", "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", //0
|
||||
"BPL", "ORA", "ST1", "SLO", "NOP", "ORA", "ASL", "SLO", "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", //1
|
||||
"JSR", "AND", "ST2", "RLA", "BIT", "AND", "ROL", "RLA", "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", //2
|
||||
"BMI", "AND", "ST3", "RLA", "NOP", "AND", "ROL", "RLA", "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", //3
|
||||
"RTI", "EOR", "ST4", "SRE", "NOP", "EOR", "LSR", "SRE", "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", //4
|
||||
"BVC", "EOR", "ST5", "SRE", "NOP", "EOR", "LSR", "SRE", "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", //5
|
||||
"RTS", "ADC", "ST6", "RRA", "NOP", "ADC", "ROR", "RRA", "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", //6
|
||||
"BVS", "ADC", "ST7", "RRA", "NOP", "ADC", "ROR", "RRA", "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", //7
|
||||
"NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", //8
|
||||
"BCC", "STA", "ST8", "AHX", "STY", "STA", "STX", "SAX", "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AXA", //9
|
||||
"LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", //A
|
||||
"BCS", "LDA", "ST9", "LAX", "LDY", "LDA", "LDX", "LAX", "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", //B
|
||||
"CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", //C
|
||||
"BNE", "CMP", "HLT", "DCP", "NOP", "CMP", "DEC", "DCP", "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", //D
|
||||
"CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", //E
|
||||
"BEQ", "SBC", "HL2", "ISC", "NOP", "SBC", "INC", "ISC", "SED", "SBC", "NOP", "ISC", "NOP", "SBC", "INC", "ISC" //F
|
||||
};
|
||||
|
||||
void Assembler::ProcessLine(string code, uint16_t &instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint16_t> &labels)
|
||||
{
|
||||
//Remove extra spaces as part of processing
|
||||
size_t offset = code.find_first_of(',', 0);
|
||||
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) {
|
||||
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, labelRegex)) {
|
||||
string label = match.str(1);
|
||||
string afterLabel = match.str(2);
|
||||
int32_t addr = _labelManager->GetLabelRelativeAddress(label);
|
||||
if(addr >= 0 && addr != instructionAddress) {
|
||||
//Label already exists, at another address
|
||||
output.push_back(AssemblerSpecialCodes::LabelRedefinition);
|
||||
return;
|
||||
} else {
|
||||
labels[match.str(1)] = instructionAddress;
|
||||
ProcessLine(afterLabel, instructionAddress, output, labels);
|
||||
return;
|
||||
}
|
||||
} 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) {
|
||||
LineData lineData;
|
||||
AssemblerSpecialCodes result = GetLineData(match, lineData, labels);
|
||||
if(result == AssemblerSpecialCodes::OK) {
|
||||
AssembleInstruction(lineData, instructionAddress, output);
|
||||
} else {
|
||||
output.push_back(result);
|
||||
}
|
||||
} else {
|
||||
output.push_back(AssemblerSpecialCodes::ParsingError);
|
||||
}
|
||||
}
|
||||
|
||||
AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData &lineData, std::unordered_map<string, uint16_t> &labels)
|
||||
{
|
||||
lineData.OpCode = match.str(1);
|
||||
lineData.IsImmediate = !match.str(2).empty();
|
||||
lineData.IsHex = !match.str(4).empty();
|
||||
lineData.HasComment = !match.str(8).empty();
|
||||
lineData.OperandSuffix = match.str(6);
|
||||
lineData.HasOpeningParenthesis = !match.str(3).empty();
|
||||
|
||||
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 != ' ') {
|
||||
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'))) {
|
||||
//invalid hex
|
||||
return AssemblerSpecialCodes::InvalidHex;
|
||||
}
|
||||
|
||||
lineData.Operand.push_back(c);
|
||||
} else {
|
||||
foundSpace = true;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
bool allNumeric = true;
|
||||
for(int 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')) {
|
||||
allNumeric = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allNumeric && !lineData.Operand.empty()) {
|
||||
//Operand is not empty, and it only contains decimal values
|
||||
lineData.IsDecimal = true;
|
||||
} else {
|
||||
lineData.IsDecimal = false;
|
||||
}
|
||||
}
|
||||
|
||||
return GetAddrModeAndOperandSize(lineData, labels);
|
||||
}
|
||||
|
||||
AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData &lineData, std::unordered_map<string, uint16_t> &labels)
|
||||
{
|
||||
int opSize = 0;
|
||||
bool invalid = false;
|
||||
string operand = lineData.Operand;
|
||||
|
||||
if(lineData.IsHex) {
|
||||
if(operand.size() == 0) {
|
||||
return AssemblerSpecialCodes::MissingOperand;
|
||||
} else if(operand.size() <= 2) {
|
||||
opSize = 1;
|
||||
} else if(operand.size() <= 4) {
|
||||
opSize = 2;
|
||||
} else {
|
||||
return AssemblerSpecialCodes::OperandOutOfRange;
|
||||
}
|
||||
} else if(lineData.IsDecimal) {
|
||||
int value = std::stoi(operand.c_str());
|
||||
if(value < -32768) {
|
||||
//< -32768 is invalid
|
||||
return AssemblerSpecialCodes::OperandOutOfRange;
|
||||
} else if(value < -128) {
|
||||
//-32768 to -129 is 2 bytes
|
||||
opSize = 2;
|
||||
} else if(value <= 255) {
|
||||
//-128 to 255 is 2 bytes
|
||||
opSize = 1;
|
||||
} else if(value <= 65535) {
|
||||
//256 to 65535 is 2 bytes
|
||||
opSize = 2;
|
||||
} else {
|
||||
//> 65535 is invalid
|
||||
return AssemblerSpecialCodes::OperandOutOfRange;
|
||||
}
|
||||
} else if(!operand.empty()) {
|
||||
//Check if the operand is a known label
|
||||
int32_t addr = _labelManager->GetLabelRelativeAddress(operand);
|
||||
if(addr >= 256) {
|
||||
lineData.Operand = HexUtilities::ToHex((uint16_t)addr);
|
||||
lineData.IsHex = true;
|
||||
opSize = 2;
|
||||
} else if(addr >= 0) {
|
||||
lineData.Operand = HexUtilities::ToHex((uint8_t)addr);
|
||||
lineData.IsHex = true;
|
||||
opSize = 1;
|
||||
} else {
|
||||
auto findResult = labels.find(operand);
|
||||
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) {
|
||||
//Allow optional "A" after AddrMode == Accumulator instructions
|
||||
lineData.Mode = AddrMode::Acc;
|
||||
opSize = 0;
|
||||
} else {
|
||||
return AssemblerSpecialCodes::UnknownLabel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//No operand
|
||||
opSize = 0;
|
||||
}
|
||||
|
||||
if(lineData.Mode == AddrMode::None) {
|
||||
if(lineData.IsImmediate) {
|
||||
if(lineData.HasOpeningParenthesis || opSize == 0) {
|
||||
invalid = true;
|
||||
}
|
||||
lineData.Mode = AddrMode::Imm; //or Rel
|
||||
} else if(lineData.HasOpeningParenthesis) {
|
||||
if(lineData.OperandSuffix.compare(")") == 0) {
|
||||
opSize = 2;
|
||||
lineData.Mode = AddrMode::Ind;
|
||||
} else if(lineData.OperandSuffix.compare(",X)") == 0) {
|
||||
opSize = 1;
|
||||
lineData.Mode = AddrMode::IndX;
|
||||
} else if(lineData.OperandSuffix.compare("),Y") == 0) {
|
||||
opSize = 1;
|
||||
lineData.Mode = AddrMode::IndY;
|
||||
} else {
|
||||
invalid = true;
|
||||
}
|
||||
} else {
|
||||
if(lineData.OperandSuffix.compare(",X") == 0) {
|
||||
if(opSize == 2) {
|
||||
lineData.Mode = AddrMode::AbsX;
|
||||
} else if(opSize == 1) {
|
||||
lineData.Mode = AddrMode::ZeroX;
|
||||
} else {
|
||||
invalid = true;
|
||||
}
|
||||
} else if(lineData.OperandSuffix.compare(",Y") == 0) {
|
||||
if(opSize == 2) {
|
||||
lineData.Mode = AddrMode::AbsY;
|
||||
} else if(opSize == 1) {
|
||||
lineData.Mode = AddrMode::ZeroY;
|
||||
} else {
|
||||
invalid = true;
|
||||
}
|
||||
} else if(lineData.OperandSuffix.empty()) {
|
||||
if(opSize == 0) {
|
||||
lineData.Mode = AddrMode::Imp; //or Acc
|
||||
} else if(opSize == 2) {
|
||||
lineData.Mode = AddrMode::Abs;
|
||||
} else if(opSize == 1) {
|
||||
lineData.Mode = AddrMode::Zero;
|
||||
} else {
|
||||
invalid = true;
|
||||
}
|
||||
} else {
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lineData.Mode == AddrMode::None) {
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
lineData.OperandSize = opSize;
|
||||
|
||||
return invalid ? AssemblerSpecialCodes::ParsingError : AssemblerSpecialCodes::OK;
|
||||
}
|
||||
|
||||
void Assembler::AssembleInstruction(LineData &lineData, uint16_t &instructionAddress, vector<int16_t>& output)
|
||||
{
|
||||
bool foundMatch = false;
|
||||
if(lineData.Mode == AddrMode::Imp && lineData.OpCode.compare("NOP") == 0) {
|
||||
//NOP has multiple name+addressing type collisions, the "official" NOP is 0xEA
|
||||
output.push_back(0xEA);
|
||||
instructionAddress++;
|
||||
foundMatch = true;
|
||||
} else {
|
||||
for(uint8_t i = 0; i < 255; i++) {
|
||||
AddrMode opMode = DisassemblyInfo::OPMode[i];
|
||||
if(lineData.OpCode.compare(opName[i]) == 0) {
|
||||
bool modeMatch = opMode == lineData.Mode;
|
||||
if(!modeMatch) {
|
||||
if(lineData.Mode == AddrMode::Imp && opMode == AddrMode::Acc ||
|
||||
lineData.Mode == AddrMode::AbsY && opMode == AddrMode::AbsYW ||
|
||||
lineData.Mode == AddrMode::AbsX && opMode == AddrMode::AbsXW) {
|
||||
modeMatch = true;
|
||||
} else if(lineData.Mode == AddrMode::Abs && opMode == AddrMode::Rel ||
|
||||
lineData.Mode == AddrMode::Imm && opMode == AddrMode::Rel) {
|
||||
|
||||
if(lineData.OperandSize == 2) {
|
||||
if(lineData.Mode == AddrMode::Imm) {
|
||||
//Hardcoded jump values must be 1-byte
|
||||
output.push_back(AssemblerSpecialCodes::OutOfRangeJump);
|
||||
return;
|
||||
} else {
|
||||
modeMatch = true;
|
||||
|
||||
//Convert "absolute" jump to a relative jump
|
||||
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
|
||||
|
||||
int16_t addressGap = value - (instructionAddress + 2);
|
||||
if(addressGap > 127 || addressGap < -128) {
|
||||
//Gap too long, can't jump that far
|
||||
output.push_back(AssemblerSpecialCodes::OutOfRangeJump);
|
||||
return;
|
||||
}
|
||||
|
||||
//Update data to match relative jump
|
||||
lineData.OperandSize = 1;
|
||||
lineData.IsHex = true;
|
||||
lineData.Operand = HexUtilities::ToHex((uint8_t)addressGap);
|
||||
}
|
||||
} else {
|
||||
//Accept 1-byte relative jumps
|
||||
modeMatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(modeMatch) {
|
||||
output.push_back(i);
|
||||
instructionAddress += (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) {
|
||||
int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand);
|
||||
output.push_back(value & 0xFF);
|
||||
output.push_back((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
foundMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundMatch) {
|
||||
output.push_back(AssemblerSpecialCodes::InvalidInstruction);
|
||||
} else {
|
||||
output.push_back(AssemblerSpecialCodes::EndOfLine);
|
||||
}
|
||||
}
|
||||
|
||||
Assembler::Assembler(shared_ptr<LabelManager> labelManager)
|
||||
{
|
||||
_labelManager = labelManager;
|
||||
}
|
||||
|
||||
uint32_t Assembler::AssembleCode(string code, uint16_t startAddress, int16_t * assembledCode)
|
||||
{
|
||||
std::unordered_map<string, uint16_t> temporaryLabels;
|
||||
|
||||
size_t i = 0;
|
||||
vector<int16_t> output;
|
||||
output.reserve(1000);
|
||||
|
||||
while(i < code.size()) {
|
||||
size_t offset = code.find_first_of('\n', i);
|
||||
string line;
|
||||
if(offset != string::npos) {
|
||||
line = code.substr(i, offset - i);
|
||||
i = offset + 1;
|
||||
} else {
|
||||
line = code.substr(i);
|
||||
i = code.size();
|
||||
}
|
||||
|
||||
ProcessLine(line, startAddress, output, temporaryLabels);
|
||||
}
|
||||
|
||||
memcpy(assembledCode, output.data(), output.size() * sizeof(uint16_t));
|
||||
return (uint32_t)output.size();
|
||||
}
|
51
Core/Assembler.h
Normal file
51
Core/Assembler.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <regex>
|
||||
#include "CPU.h"
|
||||
|
||||
class LabelManager;
|
||||
|
||||
struct LineData
|
||||
{
|
||||
string OpCode;
|
||||
string Operand;
|
||||
string OperandSuffix;
|
||||
AddrMode Mode = AddrMode::None;
|
||||
int OperandSize = 0;
|
||||
bool IsHex = false;
|
||||
bool IsDecimal = false;
|
||||
bool IsImmediate = false;
|
||||
bool HasComment = false;
|
||||
bool HasOpeningParenthesis = false;
|
||||
};
|
||||
|
||||
enum AssemblerSpecialCodes
|
||||
{
|
||||
OK = 0,
|
||||
EndOfLine = -1,
|
||||
ParsingError = -2,
|
||||
OutOfRangeJump = -3,
|
||||
LabelRedefinition = -4,
|
||||
MissingOperand = -5,
|
||||
OperandOutOfRange = -6,
|
||||
InvalidHex = -7,
|
||||
InvalidSpaces = -8,
|
||||
TrailingText = -9,
|
||||
UnknownLabel = -10,
|
||||
InvalidInstruction = -11,
|
||||
};
|
||||
|
||||
class Assembler
|
||||
{
|
||||
private:
|
||||
shared_ptr<LabelManager> _labelManager;
|
||||
void ProcessLine(string code, uint16_t &instructionAddress, vector<int16_t>& output, std::unordered_map<string, uint16_t> &labels);
|
||||
AssemblerSpecialCodes GetLineData(std::smatch match, LineData &lineData, std::unordered_map<string, uint16_t> &labels);
|
||||
AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData &lineData, std::unordered_map<string, uint16_t> &labels);
|
||||
void AssembleInstruction(LineData &lineData, uint16_t &instructionAddress, vector<int16_t>& output);
|
||||
|
||||
public:
|
||||
Assembler(shared_ptr<LabelManager> labelManager);
|
||||
|
||||
uint32_t AssembleCode(string code, uint16_t startAddress, int16_t* assembledCode);
|
||||
};
|
|
@ -409,6 +409,7 @@
|
|||
<ClInclude Include="ActionEnterprises.h" />
|
||||
<ClInclude Include="APU.h" />
|
||||
<ClInclude Include="ArkanoidController.h" />
|
||||
<ClInclude Include="Assembler.h" />
|
||||
<ClInclude Include="AutoRomTest.h" />
|
||||
<ClInclude Include="AutoSaveManager.h" />
|
||||
<ClInclude Include="AviRecorder.h" />
|
||||
|
@ -753,6 +754,7 @@
|
|||
<ClCompile Include="APU.cpp" />
|
||||
<ClCompile Include="ApuLengthCounter.cpp" />
|
||||
<ClCompile Include="ArkanoidController.cpp" />
|
||||
<ClCompile Include="Assembler.cpp" />
|
||||
<ClCompile Include="AutoRomTest.cpp" />
|
||||
<ClCompile Include="AutoSaveManager.cpp" />
|
||||
<ClCompile Include="AviRecorder.cpp" />
|
||||
|
|
|
@ -1123,6 +1123,9 @@
|
|||
<ClInclude Include="CpuState.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Assembler.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1317,5 +1320,8 @@
|
|||
<ClCompile Include="AviRecorder.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Assembler.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -14,6 +14,7 @@
|
|||
#include "MemoryDumper.h"
|
||||
#include "MemoryAccessCounter.h"
|
||||
#include "Profiler.h"
|
||||
#include "Assembler.h"
|
||||
|
||||
Debugger* Debugger::Instance = nullptr;
|
||||
const int Debugger::BreakpointTypeCount;
|
||||
|
@ -28,6 +29,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_mapper = mapper;
|
||||
|
||||
_labelManager.reset(new LabelManager(_mapper));
|
||||
_assembler.reset(new Assembler(_labelManager));
|
||||
_disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetMemorySize(DebugMemoryType::PrgRom), mapper->GetWorkRam(), mapper->GetMemorySize(DebugMemoryType::WorkRam), this));
|
||||
_codeDataLogger.reset(new CodeDataLogger(mapper->GetMemorySize(DebugMemoryType::PrgRom), mapper->GetMemorySize(DebugMemoryType::ChrRom)));
|
||||
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, _mapper, _codeDataLogger, this));
|
||||
|
@ -538,28 +540,17 @@ void Debugger::Run()
|
|||
_ppuStepCount = -1;
|
||||
}
|
||||
|
||||
bool Debugger::IsCodeChanged()
|
||||
{
|
||||
string output = GenerateOutput();
|
||||
if(_outputCache.compare(output) == 0) {
|
||||
return false;
|
||||
} else {
|
||||
_outputCache = output;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
string Debugger::GenerateOutput()
|
||||
void Debugger::GenerateCodeOutput()
|
||||
{
|
||||
State cpuState = _cpu->GetState();
|
||||
string output;
|
||||
output.reserve(10000);
|
||||
_disassemblerOutput.clear();
|
||||
_disassemblerOutput.reserve(10000);
|
||||
|
||||
bool showEffectiveAddresses = CheckFlag(DebuggerFlags::ShowEffectiveAddresses);
|
||||
bool showOnlyDiassembledCode = CheckFlag(DebuggerFlags::ShowOnlyDisassembledCode);
|
||||
|
||||
//Get code in internal RAM
|
||||
output = _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
|
||||
_disassemblerOutput = _disassembler->GetCode(0x0000, 0x1FFF, 0x0000, PrgMemoryType::PrgRom, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
|
||||
|
||||
for(uint32_t i = 0x2000; i < 0x10000; i += 0x100) {
|
||||
//Merge all sequential ranges into 1 chunk
|
||||
|
@ -580,16 +571,15 @@ string Debugger::GenerateOutput()
|
|||
addr += 0x100;
|
||||
i+=0x100;
|
||||
}
|
||||
output += _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, memoryType, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
|
||||
_disassemblerOutput += _disassembler->GetCode(startAddr, endAddr, startMemoryAddr, memoryType, showEffectiveAddresses, showOnlyDiassembledCode, cpuState, _memoryManager, _labelManager);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
string* Debugger::GetCode()
|
||||
const char* Debugger::GetCode()
|
||||
{
|
||||
return &_outputCache;
|
||||
GenerateCodeOutput();
|
||||
return _disassemblerOutput.c_str();
|
||||
}
|
||||
|
||||
int32_t Debugger::GetRelativeAddress(uint32_t addr, AddressType type)
|
||||
|
@ -670,6 +660,11 @@ void Debugger::GetFunctionEntryPoints(int32_t* entryPoints)
|
|||
entryPoints[i] = -1;
|
||||
}
|
||||
|
||||
shared_ptr<Assembler> Debugger::GetAssembler()
|
||||
{
|
||||
return _assembler;
|
||||
}
|
||||
|
||||
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
|
||||
{
|
||||
return _traceLogger;
|
||||
|
|
|
@ -19,6 +19,7 @@ class CPU;
|
|||
class PPU;
|
||||
class MemoryManager;
|
||||
class Console;
|
||||
class Assembler;
|
||||
class Disassembler;
|
||||
class LabelManager;
|
||||
class MemoryDumper;
|
||||
|
@ -33,6 +34,7 @@ private:
|
|||
const static int BreakpointTypeCount = 6;
|
||||
|
||||
unique_ptr<Disassembler> _disassembler;
|
||||
shared_ptr<Assembler> _assembler;
|
||||
shared_ptr<MemoryDumper> _memoryDumper;
|
||||
shared_ptr<CodeDataLogger> _codeDataLogger;
|
||||
shared_ptr<MemoryAccessCounter> _memoryAccessCounter;
|
||||
|
@ -77,7 +79,7 @@ private:
|
|||
uint32_t _flags;
|
||||
|
||||
string _romName;
|
||||
string _outputCache;
|
||||
string _disassemblerOutput;
|
||||
atomic<int32_t> _stepCount;
|
||||
atomic<int32_t> _ppuStepCount;
|
||||
atomic<int32_t> _stepCycleCount;
|
||||
|
@ -142,9 +144,8 @@ public:
|
|||
|
||||
bool IsExecutionStopped();
|
||||
|
||||
bool IsCodeChanged();
|
||||
string GenerateOutput();
|
||||
string* GetCode();
|
||||
void GenerateCodeOutput();
|
||||
const char* GetCode();
|
||||
|
||||
int32_t GetRelativeAddress(uint32_t addr, AddressType type);
|
||||
int32_t GetAbsoluteAddress(uint32_t addr);
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
void StopTraceLogger();
|
||||
|
||||
shared_ptr<Profiler> GetProfiler();
|
||||
shared_ptr<Assembler> GetAssembler();
|
||||
shared_ptr<TraceLogger> GetTraceLogger();
|
||||
shared_ptr<MemoryDumper> GetMemoryDumper();
|
||||
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
|
||||
|
|
|
@ -210,7 +210,7 @@ int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* mem
|
|||
case AddrMode::IndYW: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1);
|
||||
uint16_t addr = memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
return addr + cpuState.Y;
|
||||
return (uint16_t)(addr + cpuState.Y);
|
||||
}
|
||||
|
||||
case AddrMode::Ind: {
|
||||
|
@ -220,12 +220,12 @@ int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* mem
|
|||
|
||||
case AddrMode::AbsX:
|
||||
case AddrMode::AbsXW: {
|
||||
return (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.X;
|
||||
return (uint16_t)((*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.X) & 0xFFFF;
|
||||
}
|
||||
|
||||
case AddrMode::AbsY:
|
||||
case AddrMode::AbsYW: {
|
||||
return (*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.Y;
|
||||
return (uint16_t)((*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.Y) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "MessageManager.h"
|
||||
|
|
107
GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs
generated
107
GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs
generated
|
@ -29,19 +29,21 @@
|
|||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.contextMenuCode = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.mnuEditSubroutine = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuShowNextStatement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuSetNextStatement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuShowLineNotes = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuPrgAddressReplace = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuPrgAddressBelow = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuHidePrgAddresses = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowCodeNotes = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowByteCodeOnLeft = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowByteCodeBelow = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuHideByteCode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowLineNotes = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuPrgAddressReplace = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuPrgAddressBelow = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuHidePrgAddresses = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuEditLabel = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -80,6 +82,8 @@
|
|||
// contextMenuCode
|
||||
//
|
||||
this.contextMenuCode.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuEditSubroutine,
|
||||
this.toolStripMenuItem7,
|
||||
this.mnuShowNextStatement,
|
||||
this.mnuSetNextStatement,
|
||||
this.toolStripMenuItem1,
|
||||
|
@ -96,9 +100,24 @@
|
|||
this.mnuNavigateBackward,
|
||||
this.mnuNavigateForward});
|
||||
this.contextMenuCode.Name = "contextMenuWatch";
|
||||
this.contextMenuCode.Size = new System.Drawing.Size(259, 270);
|
||||
this.contextMenuCode.Size = new System.Drawing.Size(259, 320);
|
||||
this.contextMenuCode.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.contextMenuCode_Closed);
|
||||
this.contextMenuCode.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuCode_Opening);
|
||||
//
|
||||
// mnuEditSubroutine
|
||||
//
|
||||
this.mnuEditSubroutine.Image = global::Mesen.GUI.Properties.Resources.Edit;
|
||||
this.mnuEditSubroutine.Name = "mnuEditSubroutine";
|
||||
this.mnuEditSubroutine.ShortcutKeys = System.Windows.Forms.Keys.F4;
|
||||
this.mnuEditSubroutine.Size = new System.Drawing.Size(258, 22);
|
||||
this.mnuEditSubroutine.Text = "Edit subroutine";
|
||||
this.mnuEditSubroutine.Click += new System.EventHandler(this.mnuEditSubroutine_Click);
|
||||
//
|
||||
// toolStripMenuItem7
|
||||
//
|
||||
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
|
||||
this.toolStripMenuItem7.Size = new System.Drawing.Size(255, 6);
|
||||
//
|
||||
// mnuShowNextStatement
|
||||
//
|
||||
this.mnuShowNextStatement.Name = "mnuShowNextStatement";
|
||||
|
@ -122,6 +141,43 @@
|
|||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(255, 6);
|
||||
//
|
||||
// mnuShowCodeNotes
|
||||
//
|
||||
this.mnuShowCodeNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuShowByteCodeOnLeft,
|
||||
this.mnuShowByteCodeBelow,
|
||||
this.toolStripMenuItem5,
|
||||
this.mnuHideByteCode});
|
||||
this.mnuShowCodeNotes.Name = "mnuShowCodeNotes";
|
||||
this.mnuShowCodeNotes.Size = new System.Drawing.Size(258, 22);
|
||||
this.mnuShowCodeNotes.Text = "Byte Code Display";
|
||||
//
|
||||
// mnuShowByteCodeOnLeft
|
||||
//
|
||||
this.mnuShowByteCodeOnLeft.Name = "mnuShowByteCodeOnLeft";
|
||||
this.mnuShowByteCodeOnLeft.Size = new System.Drawing.Size(130, 22);
|
||||
this.mnuShowByteCodeOnLeft.Text = "On the left";
|
||||
this.mnuShowByteCodeOnLeft.Click += new System.EventHandler(this.mnuShowByteCodeOnLeft_Click);
|
||||
//
|
||||
// mnuShowByteCodeBelow
|
||||
//
|
||||
this.mnuShowByteCodeBelow.Name = "mnuShowByteCodeBelow";
|
||||
this.mnuShowByteCodeBelow.Size = new System.Drawing.Size(130, 22);
|
||||
this.mnuShowByteCodeBelow.Text = "Below";
|
||||
this.mnuShowByteCodeBelow.Click += new System.EventHandler(this.mnuShowByteCodeBelow_Click);
|
||||
//
|
||||
// toolStripMenuItem5
|
||||
//
|
||||
this.toolStripMenuItem5.Name = "toolStripMenuItem5";
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(127, 6);
|
||||
//
|
||||
// mnuHideByteCode
|
||||
//
|
||||
this.mnuHideByteCode.Name = "mnuHideByteCode";
|
||||
this.mnuHideByteCode.Size = new System.Drawing.Size(130, 22);
|
||||
this.mnuHideByteCode.Text = "Hidden";
|
||||
this.mnuHideByteCode.Click += new System.EventHandler(this.mnuHideByteCode_Click);
|
||||
//
|
||||
// mnuShowLineNotes
|
||||
//
|
||||
this.mnuShowLineNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
|
@ -160,43 +216,6 @@
|
|||
this.mnuHidePrgAddresses.Text = "Hidden";
|
||||
this.mnuHidePrgAddresses.Click += new System.EventHandler(this.mnuHidePrgAddresses_Click);
|
||||
//
|
||||
// mnuShowCodeNotes
|
||||
//
|
||||
this.mnuShowCodeNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuShowByteCodeOnLeft,
|
||||
this.mnuShowByteCodeBelow,
|
||||
this.toolStripMenuItem5,
|
||||
this.mnuHideByteCode});
|
||||
this.mnuShowCodeNotes.Name = "mnuShowCodeNotes";
|
||||
this.mnuShowCodeNotes.Size = new System.Drawing.Size(258, 22);
|
||||
this.mnuShowCodeNotes.Text = "Byte Code Display";
|
||||
//
|
||||
// mnuShowByteCodeOnLeft
|
||||
//
|
||||
this.mnuShowByteCodeOnLeft.Name = "mnuShowByteCodeOnLeft";
|
||||
this.mnuShowByteCodeOnLeft.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuShowByteCodeOnLeft.Text = "On the left";
|
||||
this.mnuShowByteCodeOnLeft.Click += new System.EventHandler(this.mnuShowByteCodeOnLeft_Click);
|
||||
//
|
||||
// mnuShowByteCodeBelow
|
||||
//
|
||||
this.mnuShowByteCodeBelow.Name = "mnuShowByteCodeBelow";
|
||||
this.mnuShowByteCodeBelow.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuShowByteCodeBelow.Text = "Below";
|
||||
this.mnuShowByteCodeBelow.Click += new System.EventHandler(this.mnuShowByteCodeBelow_Click);
|
||||
//
|
||||
// toolStripMenuItem5
|
||||
//
|
||||
this.toolStripMenuItem5.Name = "toolStripMenuItem5";
|
||||
this.toolStripMenuItem5.Size = new System.Drawing.Size(149, 6);
|
||||
//
|
||||
// mnuHideByteCode
|
||||
//
|
||||
this.mnuHideByteCode.Name = "mnuHideByteCode";
|
||||
this.mnuHideByteCode.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuHideByteCode.Text = "Hidden";
|
||||
this.mnuHideByteCode.Click += new System.EventHandler(this.mnuHideByteCode_Click);
|
||||
//
|
||||
// toolStripMenuItem2
|
||||
//
|
||||
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
|
||||
|
@ -488,5 +507,7 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuHidePrgAddresses;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem6;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuEditSubroutine;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
public delegate void AddressEventHandler(AddressEventArgs args);
|
||||
public delegate void WatchEventHandler(WatchEventArgs args);
|
||||
public delegate void AssemblerEventHandler(AssemblerEventArgs args);
|
||||
public event AssemblerEventHandler OnEditCode;
|
||||
public event AddressEventHandler OnSetNextStatement;
|
||||
private DebugViewInfo _config;
|
||||
private HashSet<int> _unexecutedAddresses = new HashSet<int>();
|
||||
|
@ -164,6 +166,46 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlCodeViewer.EndUpdate();
|
||||
}
|
||||
|
||||
Dictionary<int, Tuple<string, string>> _codeContent = new Dictionary<int, Tuple<string, string>>();
|
||||
Dictionary<int, int> _codeByteContentLength = new Dictionary<int, int>();
|
||||
public List<string> GetCode(out int byteLength, int startAddress, int endAddress = -1)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
byteLength = 0;
|
||||
|
||||
//TODO: Handle multi-line comments
|
||||
//TODO: Find start of function
|
||||
//TODO: Display labels in code window
|
||||
//TODO: Status bar to show cursor's current line
|
||||
//TODO: Bind "Start Address" field
|
||||
//TODO: Byte code cache doesn't update
|
||||
//TODO: Invalidate disassembly info cache / CDL file (not needed?)
|
||||
//TODO: Support .data syntax in assembler
|
||||
for(int i = startAddress; (i < endAddress || endAddress == -1) && endAddress < 65536; ) {
|
||||
Tuple<string, string> codeRow;
|
||||
if(_codeContent.TryGetValue(i, out codeRow)) {
|
||||
string code = codeRow.Item1;
|
||||
string comment = codeRow.Item2;
|
||||
if(code.StartsWith("--") || code.StartsWith("__") || code.StartsWith("[[")) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.Add(code + (comment ?? ""));
|
||||
int length = _codeByteContentLength[i];
|
||||
byteLength += length;
|
||||
i += length;
|
||||
|
||||
if(endAddress == -1 && (string.Compare(code, "RTI", true) == 0 || string.Compare(code, "RTS", true) == 0)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool UpdateCode(bool forceUpdate = false)
|
||||
{
|
||||
if(_codeChanged || forceUpdate) {
|
||||
|
@ -171,6 +213,8 @@ namespace Mesen.GUI.Debugger
|
|||
List<string> lineNumberNotes = new List<string>();
|
||||
List<string> codeNotes = new List<string>();
|
||||
List<string> codeLines = new List<string>();
|
||||
_codeContent = new Dictionary<int, Tuple<string, string>>();
|
||||
_codeByteContentLength = new Dictionary<int, int>();
|
||||
_unexecutedAddresses = new HashSet<int>();
|
||||
_speculativeCodeAddreses = new HashSet<int>();
|
||||
|
||||
|
@ -193,6 +237,10 @@ namespace Mesen.GUI.Debugger
|
|||
lineNumberNotes.Add(string.IsNullOrWhiteSpace(lineParts[2]) ? "" : lineParts[2].TrimStart('0').PadLeft(4, '0'));
|
||||
codeNotes.Add(lineParts[3]);
|
||||
codeLines.Add(lineParts[4]);
|
||||
_codeByteContentLength[relativeAddress] = lineParts[3].Count(c => c == ' ') + 1;
|
||||
|
||||
string[] codeRow = lineParts[4].Split('\x2');
|
||||
_codeContent[relativeAddress] = new Tuple<string, string>(codeRow[0].Trim(), codeRow.Length > 2 ? " " + codeRow[2].Replace(Environment.NewLine, " | ") : null);
|
||||
}
|
||||
|
||||
previousIndex = index;
|
||||
|
@ -516,6 +564,12 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
mnuShowNextStatement.Enabled = _currentActiveAddress.HasValue;
|
||||
mnuSetNextStatement.Enabled = _currentActiveAddress.HasValue;
|
||||
mnuEditSubroutine.Enabled = InteropEmu.DebugIsExecutionStopped();
|
||||
}
|
||||
|
||||
private void contextMenuCode_Closed(object sender, ToolStripDropDownClosedEventArgs e)
|
||||
{
|
||||
mnuEditSubroutine.Enabled = true;
|
||||
}
|
||||
|
||||
private void mnuShowNextStatement_Click(object sender, EventArgs e)
|
||||
|
@ -678,6 +732,16 @@ namespace Mesen.GUI.Debugger
|
|||
_config.PrgAddressPosition = PrgAddressPosition.Hidden;
|
||||
this.UpdateConfig();
|
||||
}
|
||||
|
||||
private void mnuEditSubroutine_Click(object sender, EventArgs e)
|
||||
{
|
||||
int currentLine = this.GetCurrentLine();
|
||||
if(currentLine != -1 && InteropEmu.DebugIsExecutionStopped()) {
|
||||
int byteLength;
|
||||
List<string> code = this.GetCode(out byteLength, currentLine);
|
||||
this.OnEditCode?.Invoke(new AssemblerEventArgs() { Code = string.Join(Environment.NewLine, code), StartAddress = (UInt16)currentLine, BlockLength = (UInt16)byteLength });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class WatchEventArgs : EventArgs
|
||||
|
@ -689,4 +753,11 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
public UInt32 Address { get; set; }
|
||||
}
|
||||
|
||||
public class AssemblerEventArgs : EventArgs
|
||||
{
|
||||
public string Code { get; set; }
|
||||
public UInt16 StartAddress { get; set; }
|
||||
public UInt16 BlockLength { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
320
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
Normal file
320
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
Normal file
|
@ -0,0 +1,320 @@
|
|||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
partial class frmAssembler
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ctrlHexBox = new Be.Windows.Forms.HexBox();
|
||||
this.lstErrors = new System.Windows.Forms.ListBox();
|
||||
this.grpSettings = new System.Windows.Forms.GroupBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.txtStartAddress = new System.Windows.Forms.TextBox();
|
||||
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.lblByteUsage = new System.Windows.Forms.Label();
|
||||
this.picSizeWarning = new System.Windows.Forms.PictureBox();
|
||||
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblNoChanges = new System.Windows.Forms.Label();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.txtCode = new System.Windows.Forms.RichTextBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.grpSettings.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.flowLayoutPanel1.SuspendLayout();
|
||||
this.flowLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picSizeWarning)).BeginInit();
|
||||
this.flowLayoutPanel3.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.Location = new System.Drawing.Point(279, 3);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 0;
|
||||
this.btnOk.Text = "Apply";
|
||||
this.btnOk.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(360, 3);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.ctrlHexBox, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lstErrors, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.grpSettings, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 141F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(999, 534);
|
||||
this.tableLayoutPanel1.TabIndex = 2;
|
||||
//
|
||||
// ctrlHexBox
|
||||
//
|
||||
this.ctrlHexBox.ByteColorProvider = null;
|
||||
this.ctrlHexBox.ColumnInfoVisible = true;
|
||||
this.ctrlHexBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlHexBox.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||
this.ctrlHexBox.InfoBackColor = System.Drawing.Color.DarkGray;
|
||||
this.ctrlHexBox.LineInfoVisible = true;
|
||||
this.ctrlHexBox.Location = new System.Drawing.Point(552, 3);
|
||||
this.ctrlHexBox.Name = "ctrlHexBox";
|
||||
this.ctrlHexBox.ReadOnly = true;
|
||||
this.ctrlHexBox.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255)))));
|
||||
this.ctrlHexBox.Size = new System.Drawing.Size(444, 387);
|
||||
this.ctrlHexBox.TabIndex = 1;
|
||||
this.ctrlHexBox.UseFixedBytesPerLine = true;
|
||||
this.ctrlHexBox.VScrollBarVisible = true;
|
||||
//
|
||||
// lstErrors
|
||||
//
|
||||
this.lstErrors.FormattingEnabled = true;
|
||||
this.lstErrors.Location = new System.Drawing.Point(3, 396);
|
||||
this.lstErrors.Name = "lstErrors";
|
||||
this.lstErrors.Size = new System.Drawing.Size(543, 134);
|
||||
this.lstErrors.TabIndex = 2;
|
||||
//
|
||||
// grpSettings
|
||||
//
|
||||
this.grpSettings.Controls.Add(this.tableLayoutPanel2);
|
||||
this.grpSettings.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpSettings.Location = new System.Drawing.Point(552, 396);
|
||||
this.grpSettings.Name = "grpSettings";
|
||||
this.grpSettings.Size = new System.Drawing.Size(444, 135);
|
||||
this.grpSettings.TabIndex = 3;
|
||||
this.grpSettings.TabStop = false;
|
||||
this.grpSettings.Text = "Settings";
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 1;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel1, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel2, 0, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel3, 0, 2);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 3;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(438, 116);
|
||||
this.tableLayoutPanel2.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.flowLayoutPanel1.Controls.Add(this.label1);
|
||||
this.flowLayoutPanel1.Controls.Add(this.txtStartAddress);
|
||||
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(438, 25);
|
||||
this.flowLayoutPanel1.TabIndex = 3;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(3, 6);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(81, 13);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Start address: $";
|
||||
//
|
||||
// txtStartAddress
|
||||
//
|
||||
this.txtStartAddress.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.txtStartAddress.Location = new System.Drawing.Point(84, 3);
|
||||
this.txtStartAddress.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
|
||||
this.txtStartAddress.Name = "txtStartAddress";
|
||||
this.txtStartAddress.Size = new System.Drawing.Size(65, 20);
|
||||
this.txtStartAddress.TabIndex = 1;
|
||||
//
|
||||
// flowLayoutPanel2
|
||||
//
|
||||
this.flowLayoutPanel2.Controls.Add(this.label2);
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblByteUsage);
|
||||
this.flowLayoutPanel2.Controls.Add(this.picSizeWarning);
|
||||
this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel2.Location = new System.Drawing.Point(0, 25);
|
||||
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
|
||||
this.flowLayoutPanel2.Size = new System.Drawing.Size(438, 25);
|
||||
this.flowLayoutPanel2.TabIndex = 4;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(3, 6);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(63, 13);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Byte usage:";
|
||||
//
|
||||
// lblByteUsage
|
||||
//
|
||||
this.lblByteUsage.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblByteUsage.AutoSize = true;
|
||||
this.lblByteUsage.Location = new System.Drawing.Point(72, 6);
|
||||
this.lblByteUsage.Name = "lblByteUsage";
|
||||
this.lblByteUsage.Size = new System.Drawing.Size(30, 13);
|
||||
this.lblByteUsage.TabIndex = 3;
|
||||
this.lblByteUsage.Text = "0 / 0";
|
||||
//
|
||||
// picSizeWarning
|
||||
//
|
||||
this.picSizeWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
|
||||
this.picSizeWarning.Location = new System.Drawing.Point(108, 5);
|
||||
this.picSizeWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
|
||||
this.picSizeWarning.Name = "picSizeWarning";
|
||||
this.picSizeWarning.Size = new System.Drawing.Size(18, 18);
|
||||
this.picSizeWarning.TabIndex = 10;
|
||||
this.picSizeWarning.TabStop = false;
|
||||
this.picSizeWarning.Visible = false;
|
||||
//
|
||||
// flowLayoutPanel3
|
||||
//
|
||||
this.flowLayoutPanel3.Controls.Add(this.btnCancel);
|
||||
this.flowLayoutPanel3.Controls.Add(this.btnOk);
|
||||
this.flowLayoutPanel3.Controls.Add(this.lblNoChanges);
|
||||
this.flowLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.flowLayoutPanel3.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
|
||||
this.flowLayoutPanel3.Location = new System.Drawing.Point(0, 86);
|
||||
this.flowLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel3.Name = "flowLayoutPanel3";
|
||||
this.flowLayoutPanel3.Size = new System.Drawing.Size(438, 30);
|
||||
this.flowLayoutPanel3.TabIndex = 5;
|
||||
//
|
||||
// lblNoChanges
|
||||
//
|
||||
this.lblNoChanges.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblNoChanges.AutoSize = true;
|
||||
this.lblNoChanges.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
|
||||
this.lblNoChanges.ForeColor = System.Drawing.SystemColors.GrayText;
|
||||
this.lblNoChanges.Location = new System.Drawing.Point(99, 8);
|
||||
this.lblNoChanges.Name = "lblNoChanges";
|
||||
this.lblNoChanges.Size = new System.Drawing.Size(174, 13);
|
||||
this.lblNoChanges.TabIndex = 2;
|
||||
this.lblNoChanges.Text = "Current code matches original code";
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
|
||||
this.panel1.Controls.Add(this.txtCode);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.Location = new System.Drawing.Point(3, 3);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Padding = new System.Windows.Forms.Padding(1);
|
||||
this.panel1.Size = new System.Drawing.Size(543, 387);
|
||||
this.panel1.TabIndex = 4;
|
||||
//
|
||||
// txtCode
|
||||
//
|
||||
this.txtCode.AcceptsTab = true;
|
||||
this.txtCode.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.txtCode.DetectUrls = false;
|
||||
this.txtCode.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtCode.Location = new System.Drawing.Point(1, 1);
|
||||
this.txtCode.Name = "txtCode";
|
||||
this.txtCode.Size = new System.Drawing.Size(541, 385);
|
||||
this.txtCode.TabIndex = 4;
|
||||
this.txtCode.Text = "";
|
||||
this.txtCode.WordWrap = false;
|
||||
this.txtCode.TextChanged += new System.EventHandler(this.txtCode_TextChanged);
|
||||
this.txtCode.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txtCode_KeyDown);
|
||||
//
|
||||
// frmAssembler
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(999, 534);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "frmAssembler";
|
||||
this.Text = "Assembler";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.grpSettings.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.flowLayoutPanel1.PerformLayout();
|
||||
this.flowLayoutPanel2.ResumeLayout(false);
|
||||
this.flowLayoutPanel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picSizeWarning)).EndInit();
|
||||
this.flowLayoutPanel3.ResumeLayout(false);
|
||||
this.flowLayoutPanel3.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private Be.Windows.Forms.HexBox ctrlHexBox;
|
||||
private System.Windows.Forms.ListBox lstErrors;
|
||||
private System.Windows.Forms.GroupBox grpSettings;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox txtStartAddress;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label lblByteUsage;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.PictureBox picSizeWarning;
|
||||
private System.Windows.Forms.RichTextBox txtCode;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Label lblNoChanges;
|
||||
}
|
||||
}
|
215
GUI.NET/Debugger/frmAssembler.cs
Normal file
215
GUI.NET/Debugger/frmAssembler.cs
Normal file
|
@ -0,0 +1,215 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Be.Windows.Forms;
|
||||
using Mesen.GUI.Controls;
|
||||
using Mesen.GUI.Forms;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public partial class frmAssembler : BaseForm
|
||||
{
|
||||
private UInt16 _startAddress;
|
||||
private UInt16 _blockLength;
|
||||
private bool _hasParsingErrors = false;
|
||||
private bool _containedRtiRts = false;
|
||||
private bool _isEditMode = false;
|
||||
|
||||
public frmAssembler(string code = "", UInt16 startAddress = 0, UInt16 blockLength = 0)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if(string.IsNullOrWhiteSpace(code)) {
|
||||
btnCancel.Text = "Close";
|
||||
btnOk.Enabled = false;
|
||||
btnOk.Visible = false;
|
||||
} else {
|
||||
_isEditMode = true;
|
||||
_containedRtiRts = ContainsRtiOrRts(code);
|
||||
}
|
||||
|
||||
_startAddress = startAddress;
|
||||
_blockLength = blockLength;
|
||||
|
||||
txtCode.Font = new Font(BaseControl.MonospaceFontFamily, 10);
|
||||
ctrlHexBox.Font = new Font(BaseControl.MonospaceFontFamily, 10, FontStyle.Regular);
|
||||
ctrlHexBox.SelectionForeColor = Color.White;
|
||||
ctrlHexBox.SelectionBackColor = Color.FromArgb(31, 123, 205);
|
||||
ctrlHexBox.InfoBackColor = Color.FromArgb(235, 235, 235);
|
||||
ctrlHexBox.InfoForeColor = Color.Gray;
|
||||
ctrlHexBox.Width = ctrlHexBox.RequiredWidth;
|
||||
ctrlHexBox.ByteProvider = new StaticByteProvider(new byte[0]);
|
||||
|
||||
txtStartAddress.Text = _startAddress.ToString("X4");
|
||||
txtCode.Text = code;
|
||||
txtCode.Select(0, 0);
|
||||
|
||||
toolTip.SetToolTip(picSizeWarning, "Warning: The new code exceeds the original code's length." + Environment.NewLine + "Applying this modification will overwrite other portions of the code and potentially cause problems.");
|
||||
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
private bool ContainsRtiOrRts(string code)
|
||||
{
|
||||
return Regex.IsMatch(code, "^\\s*(RTI|RTS)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
}
|
||||
|
||||
private bool SizeExceeded
|
||||
{
|
||||
get { return ctrlHexBox.ByteProvider.Length > _blockLength; }
|
||||
}
|
||||
|
||||
private bool NeedRtiRtsWarning
|
||||
{
|
||||
get { return _containedRtiRts && !ContainsRtiOrRts(txtCode.Text); }
|
||||
}
|
||||
|
||||
private bool IsIdentical
|
||||
{
|
||||
get
|
||||
{
|
||||
if(ctrlHexBox.ByteProvider.Length != _blockLength) {
|
||||
return false;
|
||||
} else {
|
||||
for(int i = 0; i < ctrlHexBox.ByteProvider.Length; i++) {
|
||||
if(InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)(_startAddress + i)) != ctrlHexBox.ByteProvider.ReadByte(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWindow()
|
||||
{
|
||||
short[] byteCode = InteropEmu.DebugAssembleCode(txtCode.Text, _startAddress);
|
||||
|
||||
List<byte> convertedByteCode = new List<byte>();
|
||||
List<string> errorList = new List<string>();
|
||||
string[] codeLines = txtCode.Text.Replace("\r", "").Split('\n');
|
||||
int line = 1;
|
||||
foreach(short s in byteCode) {
|
||||
if(s >= 0) {
|
||||
convertedByteCode.Add((byte)s);
|
||||
} else if(s == (int)AssemblerSpecialCodes.EndOfLine) {
|
||||
line++;
|
||||
} else if(s < (int)AssemblerSpecialCodes.EndOfLine) {
|
||||
string message = "unknown error";
|
||||
switch((AssemblerSpecialCodes)s) {
|
||||
case AssemblerSpecialCodes.ParsingError: message = "Invalid syntax"; break;
|
||||
case AssemblerSpecialCodes.OutOfRangeJump: message = "Relative jump is out of range (-128 to 127)"; break;
|
||||
case AssemblerSpecialCodes.LabelRedefinition: message = "Cannot redefine an existing label"; break;
|
||||
case AssemblerSpecialCodes.MissingOperand: message = "Operand is missing"; break;
|
||||
case AssemblerSpecialCodes.OperandOutOfRange: message = "Operand is out of range (invalid value)"; break;
|
||||
case AssemblerSpecialCodes.InvalidHex: message = "Hexadecimal string is invalid"; break;
|
||||
case AssemblerSpecialCodes.InvalidSpaces: message = "Operand cannot contain spaces"; break;
|
||||
case AssemblerSpecialCodes.TrailingText: message = "Invalid text trailing at the end of line"; break;
|
||||
case AssemblerSpecialCodes.UnknownLabel: message = "Unknown label"; break;
|
||||
case AssemblerSpecialCodes.InvalidInstruction: message = "Invalid instruction"; break;
|
||||
}
|
||||
errorList.Add("Line " + line.ToString() + ": " + message + " - " + codeLines[line-1]);
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
_hasParsingErrors = errorList.Count > 0;
|
||||
|
||||
lstErrors.BeginUpdate();
|
||||
lstErrors.Items.Clear();
|
||||
lstErrors.Items.AddRange(errorList.ToArray());
|
||||
lstErrors.EndUpdate();
|
||||
|
||||
ctrlHexBox.ByteProvider = new StaticByteProvider(convertedByteCode.ToArray());
|
||||
|
||||
if(_isEditMode) {
|
||||
lblByteUsage.Text = ctrlHexBox.ByteProvider.Length.ToString() + " / " + _blockLength.ToString();
|
||||
lblByteUsage.ForeColor = SizeExceeded ? Color.Red : Color.Black;
|
||||
picSizeWarning.Visible = SizeExceeded;
|
||||
btnOk.Image = _hasParsingErrors || NeedRtiRtsWarning || SizeExceeded ? Properties.Resources.Warning : null;
|
||||
|
||||
bool isIdentical = IsIdentical;
|
||||
lblNoChanges.Visible = isIdentical;
|
||||
btnOk.Enabled = !isIdentical;
|
||||
} else {
|
||||
lblByteUsage.Text = ctrlHexBox.ByteProvider.Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void txtCode_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
private void txtCode_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if(e.Control && e.KeyCode == Keys.V || e.Shift && e.KeyCode == Keys.Insert) {
|
||||
txtCode.Paste(DataFormats.GetFormat("Text"));
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
List<string> warningMessages = new List<string>();
|
||||
if(_hasParsingErrors) {
|
||||
warningMessages.Add("Warning: The code contains parsing errors - lines with errors will be ignored.");
|
||||
}
|
||||
if(SizeExceeded) {
|
||||
warningMessages.Add("Warning: The new code exceeds the original code's length." + Environment.NewLine + "Applying this modification will overwrite other portions of the code and potentially cause problems.");
|
||||
}
|
||||
if(NeedRtiRtsWarning) {
|
||||
warningMessages.Add("Warning: The code originally contained an RTI/RTS instruction and it no longer does - this will probably cause problems.");
|
||||
}
|
||||
|
||||
if(warningMessages.Count == 0 || MessageBox.Show(string.Join(Environment.NewLine+Environment.NewLine, warningMessages.ToArray()) + Environment.NewLine + Environment.NewLine + "OK?", "Warning", MessageBoxButtons.OKCancel) == DialogResult.OK) {
|
||||
byte lastByte = ctrlHexBox.ByteProvider.ReadByte(ctrlHexBox.ByteProvider.Length - 1);
|
||||
bool endsWithRtiRts = lastByte == 0x40 || lastByte == 0x60;
|
||||
int byteGap = (int)(_blockLength - ctrlHexBox.ByteProvider.Length);
|
||||
List<byte> bytes = new List<byte>(((StaticByteProvider)ctrlHexBox.ByteProvider).Bytes);
|
||||
if(byteGap > 0) {
|
||||
//Pad data with NOPs as needed
|
||||
int insertPoint = endsWithRtiRts ? bytes.Count - 2 : bytes.Count - 1;
|
||||
for(int i = 0; i < byteGap; i++) {
|
||||
bytes.Insert(insertPoint, 0xEA); //0xEA = NOP
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < bytes.Count; i++) {
|
||||
InteropEmu.DebugSetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)(_startAddress + i), bytes[i]);
|
||||
}
|
||||
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
enum AssemblerSpecialCodes
|
||||
{
|
||||
OK = 0,
|
||||
EndOfLine = -1,
|
||||
ParsingError = -2,
|
||||
OutOfRangeJump = -3,
|
||||
LabelRedefinition = -4,
|
||||
MissingOperand = -5,
|
||||
OperandOutOfRange = -6,
|
||||
InvalidHex = -7,
|
||||
InvalidSpaces = -8,
|
||||
TrailingText = -9,
|
||||
UnknownLabel = -10,
|
||||
InvalidInstruction = -11,
|
||||
}
|
||||
}
|
||||
}
|
123
GUI.NET/Debugger/frmAssembler.resx
Normal file
123
GUI.NET/Debugger/frmAssembler.resx
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
32
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
32
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
|
@ -147,6 +147,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.lblChrAnalysisResult = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
|
||||
this.mnuAssembler = new System.Windows.Forms.ToolStripMenuItem();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||
this.splitContainer.Panel1.SuspendLayout();
|
||||
this.splitContainer.Panel2.SuspendLayout();
|
||||
|
@ -215,7 +216,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists);
|
||||
this.ctrlSplitContainerTop.Panel2MinSize = 150;
|
||||
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1260, 390);
|
||||
this.ctrlSplitContainerTop.SplitterDistance = 927;
|
||||
this.ctrlSplitContainerTop.SplitterDistance = 924;
|
||||
this.ctrlSplitContainerTop.SplitterWidth = 7;
|
||||
this.ctrlSplitContainerTop.TabIndex = 3;
|
||||
this.ctrlSplitContainerTop.PanelCollapsed += new System.EventHandler(this.ctrlSplitContainerTop_PanelCollapsed);
|
||||
|
@ -236,7 +237,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.tlpTop.Name = "tlpTop";
|
||||
this.tlpTop.RowCount = 1;
|
||||
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tlpTop.Size = new System.Drawing.Size(927, 390);
|
||||
this.tlpTop.Size = new System.Drawing.Size(924, 390);
|
||||
this.tlpTop.TabIndex = 2;
|
||||
//
|
||||
// ctrlDebuggerCode
|
||||
|
@ -245,15 +246,16 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlDebuggerCode.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlDebuggerCode.Location = new System.Drawing.Point(3, 3);
|
||||
this.ctrlDebuggerCode.Name = "ctrlDebuggerCode";
|
||||
this.ctrlDebuggerCode.Size = new System.Drawing.Size(489, 384);
|
||||
this.ctrlDebuggerCode.Size = new System.Drawing.Size(486, 384);
|
||||
this.ctrlDebuggerCode.TabIndex = 2;
|
||||
this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode);
|
||||
this.ctrlDebuggerCode.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement);
|
||||
this.ctrlDebuggerCode.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter);
|
||||
//
|
||||
// ctrlConsoleStatus
|
||||
//
|
||||
this.ctrlConsoleStatus.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlConsoleStatus.Location = new System.Drawing.Point(495, 0);
|
||||
this.ctrlConsoleStatus.Location = new System.Drawing.Point(492, 0);
|
||||
this.ctrlConsoleStatus.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.ctrlConsoleStatus.Name = "ctrlConsoleStatus";
|
||||
this.ctrlConsoleStatus.Size = new System.Drawing.Size(432, 390);
|
||||
|
@ -264,11 +266,12 @@ namespace Mesen.GUI.Debugger
|
|||
//
|
||||
this.ctrlDebuggerCodeSplit.Code = null;
|
||||
this.ctrlDebuggerCodeSplit.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(498, 3);
|
||||
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(495, 3);
|
||||
this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit";
|
||||
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 384);
|
||||
this.ctrlDebuggerCodeSplit.TabIndex = 4;
|
||||
this.ctrlDebuggerCodeSplit.Visible = false;
|
||||
this.ctrlDebuggerCodeSplit.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode);
|
||||
this.ctrlDebuggerCodeSplit.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement);
|
||||
this.ctrlDebuggerCodeSplit.Enter += new System.EventHandler(this.ctrlDebuggerCodeSplit_Enter);
|
||||
//
|
||||
|
@ -285,7 +288,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.tlpFunctionLabelLists.RowCount = 2;
|
||||
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(326, 390);
|
||||
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(329, 390);
|
||||
this.tlpFunctionLabelLists.TabIndex = 5;
|
||||
//
|
||||
// grpLabels
|
||||
|
@ -294,7 +297,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpLabels.Location = new System.Drawing.Point(3, 198);
|
||||
this.grpLabels.Name = "grpLabels";
|
||||
this.grpLabels.Size = new System.Drawing.Size(320, 189);
|
||||
this.grpLabels.Size = new System.Drawing.Size(323, 189);
|
||||
this.grpLabels.TabIndex = 6;
|
||||
this.grpLabels.TabStop = false;
|
||||
this.grpLabels.Text = "Labels";
|
||||
|
@ -304,7 +307,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlLabelList.Name = "ctrlLabelList";
|
||||
this.ctrlLabelList.Size = new System.Drawing.Size(314, 170);
|
||||
this.ctrlLabelList.Size = new System.Drawing.Size(317, 170);
|
||||
this.ctrlLabelList.TabIndex = 0;
|
||||
this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence);
|
||||
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected);
|
||||
|
@ -315,7 +318,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpFunctions.Location = new System.Drawing.Point(3, 3);
|
||||
this.grpFunctions.Name = "grpFunctions";
|
||||
this.grpFunctions.Size = new System.Drawing.Size(320, 189);
|
||||
this.grpFunctions.Size = new System.Drawing.Size(323, 189);
|
||||
this.grpFunctions.TabIndex = 5;
|
||||
this.grpFunctions.TabStop = false;
|
||||
this.grpFunctions.Text = "Functions";
|
||||
|
@ -325,7 +328,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16);
|
||||
this.ctrlFunctionList.Name = "ctrlFunctionList";
|
||||
this.ctrlFunctionList.Size = new System.Drawing.Size(314, 170);
|
||||
this.ctrlFunctionList.Size = new System.Drawing.Size(317, 170);
|
||||
this.ctrlFunctionList.TabIndex = 0;
|
||||
this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence);
|
||||
this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected);
|
||||
|
@ -986,6 +989,7 @@ namespace Mesen.GUI.Debugger
|
|||
this.mnuMemoryViewer,
|
||||
this.mnuPpuViewer,
|
||||
this.mnuTraceLogger,
|
||||
this.mnuAssembler,
|
||||
this.toolStripMenuItem13,
|
||||
this.mnuCodeDataLogger});
|
||||
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
|
||||
|
@ -1154,6 +1158,13 @@ namespace Mesen.GUI.Debugger
|
|||
this.ctrlCpuMemoryMapping.Text = "ctrlMemoryMapping1";
|
||||
this.ctrlCpuMemoryMapping.Visible = false;
|
||||
//
|
||||
// mnuAssembler
|
||||
//
|
||||
this.mnuAssembler.Name = "mnuAssembler";
|
||||
this.mnuAssembler.Size = new System.Drawing.Size(196, 22);
|
||||
this.mnuAssembler.Text = "Assembler";
|
||||
this.mnuAssembler.Click += new System.EventHandler(this.mnuAssembler_Click);
|
||||
//
|
||||
// frmDebugger
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -1305,5 +1316,6 @@ namespace Mesen.GUI.Debugger
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuBreakOnBrk;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuSaveRom;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem14;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAssembler;
|
||||
}
|
||||
}
|
|
@ -295,10 +295,8 @@ namespace Mesen.GUI.Debugger
|
|||
UpdateDebuggerFlags();
|
||||
UpdateVectorAddresses();
|
||||
|
||||
if(InteropEmu.DebugIsCodeChanged()) {
|
||||
_previousCode = InteropEmu.DebugGetCode();
|
||||
ctrlDebuggerCode.Code = _previousCode;
|
||||
}
|
||||
_previousCode = InteropEmu.DebugGetCode();
|
||||
ctrlDebuggerCode.Code = _previousCode;
|
||||
|
||||
DebugState state = new DebugState();
|
||||
InteropEmu.DebugGetState(ref state);
|
||||
|
@ -358,6 +356,9 @@ namespace Mesen.GUI.Debugger
|
|||
frm.FormClosed += (obj, args) => {
|
||||
this._childForms.Remove((Form)obj);
|
||||
};
|
||||
frm.StartPosition = FormStartPosition.Manual;
|
||||
frm.Left = this.Left + this.Width / 2 - frm.Width / 2;
|
||||
frm.Top = this.Top + this.Height / 2 - frm.Height / 2;
|
||||
frm.Show();
|
||||
}
|
||||
|
||||
|
@ -437,6 +438,17 @@ namespace Mesen.GUI.Debugger
|
|||
this.UpdateDebugger();
|
||||
}
|
||||
|
||||
private void ctrlDebuggerCode_OnEditCode(AssemblerEventArgs args)
|
||||
{
|
||||
frmAssembler assembler = new frmAssembler(args.Code, args.StartAddress, args.BlockLength);
|
||||
assembler.FormClosed += (s, e) => {
|
||||
if(assembler.DialogResult == DialogResult.OK) {
|
||||
this.UpdateDebugger(false);
|
||||
}
|
||||
};
|
||||
OpenChildForm(assembler);
|
||||
}
|
||||
|
||||
private void mnuFind_Click(object sender, EventArgs e)
|
||||
{
|
||||
_lastCodeWindow.OpenSearchBox();
|
||||
|
@ -853,5 +865,10 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuAssembler_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenChildForm(new frmAssembler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,6 +375,12 @@
|
|||
<DependentUpon>ctrlWatch.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\DbgImporter.cs" />
|
||||
<Compile Include="Debugger\frmAssembler.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmAssembler.Designer.cs">
|
||||
<DependentUpon>frmAssembler.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmCodeTooltip.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -722,6 +728,9 @@
|
|||
<EmbeddedResource Include="Debugger\Controls\ctrlWatch.resx">
|
||||
<DependentUpon>ctrlWatch.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\frmAssembler.resx">
|
||||
<DependentUpon>frmAssembler.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\frmCodeTooltip.resx">
|
||||
<DependentUpon>frmCodeTooltip.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -938,6 +947,7 @@
|
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Icon.ico" />
|
||||
<None Include="Resources\Edit.png" />
|
||||
<None Include="Resources\pencil.png" />
|
||||
<None Include="Resources\pipette.png" />
|
||||
<None Include="Resources\VideoRecorder.png" />
|
||||
|
|
|
@ -182,7 +182,6 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void DebugStepOver();
|
||||
[DllImport(DLLPath)] public static extern void DebugRun();
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugIsExecutionStopped();
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugIsCodeChanged();
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetRelativeAddress(UInt32 absoluteAddr, AddressType type);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetAbsoluteAddress(UInt32 relativeAddr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugGetMemorySize(DebugMemoryType type);
|
||||
|
@ -214,6 +213,26 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper();
|
||||
public static string DebugGetCode() { return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper()); }
|
||||
|
||||
[DllImport(DLLPath, EntryPoint="DebugAssembleCode")] private static extern UInt32 DebugAssembleCodeWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string code, UInt16 startAddress, IntPtr assembledCodeBuffer);
|
||||
public static Int16[] DebugAssembleCode(string code, UInt16 startAddress)
|
||||
{
|
||||
code = code.Replace(Environment.NewLine, "\n");
|
||||
int lineCount = code.Count(c => c == '\n');
|
||||
|
||||
Int16[] assembledCode = new Int16[(lineCount + 1) * 4];
|
||||
UInt32 size = 0;
|
||||
|
||||
GCHandle hAssembledCode = GCHandle.Alloc(assembledCode, GCHandleType.Pinned);
|
||||
try {
|
||||
size = InteropEmu.DebugAssembleCodeWrapper(code, startAddress, hAssembledCode.AddrOfPinnedObject());
|
||||
} finally {
|
||||
hAssembledCode.Free();
|
||||
}
|
||||
|
||||
Array.Resize(ref assembledCode, (int)size);
|
||||
return assembledCode;
|
||||
}
|
||||
|
||||
[DllImport(DLLPath, EntryPoint="DebugGetMemoryState")] private static extern UInt32 DebugGetMemoryStateWrapper(DebugMemoryType type, IntPtr buffer);
|
||||
public static byte[] DebugGetMemoryState(DebugMemoryType type)
|
||||
{
|
||||
|
|
10
GUI.NET/Properties/Resources.Designer.cs
generated
10
GUI.NET/Properties/Resources.Designer.cs
generated
|
@ -200,6 +200,16 @@ namespace Mesen.GUI.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap Edit {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Edit", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
|
|
@ -256,4 +256,7 @@
|
|||
<data name="Pipette" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\pipette.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
BIN
GUI.NET/Resources/Edit.png
Normal file
BIN
GUI.NET/Resources/Edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 642 B |
|
@ -6,6 +6,7 @@
|
|||
#include "../Core/MemoryDumper.h"
|
||||
#include "../Core/MemoryAccessCounter.h"
|
||||
#include "../Core/Profiler.h"
|
||||
#include "../Core/Assembler.h"
|
||||
|
||||
shared_ptr<Debugger> GetDebugger()
|
||||
{
|
||||
|
@ -45,8 +46,7 @@ extern "C"
|
|||
DllExport void __stdcall DebugStepOver() { GetDebugger()->StepOver(); }
|
||||
DllExport void __stdcall DebugStepOut() { GetDebugger()->StepOut(); }
|
||||
DllExport void __stdcall DebugPpuStep(uint32_t count) { GetDebugger()->PpuStep(count); }
|
||||
DllExport bool __stdcall DebugIsCodeChanged() { return GetDebugger()->IsCodeChanged(); }
|
||||
DllExport const char* __stdcall DebugGetCode() { return GetDebugger()->GetCode()->c_str(); }
|
||||
DllExport const char* __stdcall DebugGetCode() { return GetDebugger()->GetCode(); }
|
||||
|
||||
DllExport void __stdcall DebugSetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle) { return GetDebugger()->SetPpuViewerScanlineCycle(scanline, cycle); }
|
||||
|
||||
|
@ -94,5 +94,7 @@ extern "C"
|
|||
|
||||
DllExport uint32_t __stdcall DebugGetPpuScroll() { return GetDebugger()->GetPpuScroll(); }
|
||||
|
||||
DllExport uint32_t __stdcall DebugAssembleCode(char* code, uint16_t startAddress, int16_t* assembledOutput) { return GetDebugger()->GetAssembler()->AssembleCode(code, startAddress, assembledOutput); }
|
||||
|
||||
DllExport void __stdcall DebugSaveRomToDisk(char* filename) { GetDebugger()->SaveRomToDisk(filename); }
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue