mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
Debugger: On-the-fly code running feature via assembler
This commit is contained in:
parent
e2fb36240d
commit
d72a4d8be3
16 changed files with 306 additions and 71 deletions
48
Core/CodeRunner.cpp
Normal file
48
Core/CodeRunner.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "stdafx.h"
|
||||
#include "CodeRunner.h"
|
||||
#include "Debugger.h"
|
||||
#include "DisassemblyInfo.h"
|
||||
|
||||
CodeRunner::CodeRunner(vector<uint8_t> byteCode, Debugger *debugger)
|
||||
{
|
||||
_byteCode = byteCode;
|
||||
_debugger = debugger;
|
||||
_running = true;
|
||||
|
||||
if(_byteCode.size() < 0x1000) {
|
||||
//Fill the entire $3000-$3FFF range
|
||||
_byteCode.insert(_byteCode.end(), 0x1000 - _byteCode.size(), 0xEA); //0xEA = NOP
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeRunner::IsRunning()
|
||||
{
|
||||
return _running;
|
||||
}
|
||||
|
||||
void CodeRunner::GetMemoryRanges(MemoryRanges & ranges)
|
||||
{
|
||||
ranges.SetAllowOverride();
|
||||
ranges.AddHandler(MemoryOperation::Any, CodeRunner::BaseAddress, CodeRunner::BaseAddress + 0xFFF);
|
||||
}
|
||||
|
||||
uint8_t CodeRunner::ReadRAM(uint16_t addr)
|
||||
{
|
||||
return _byteCode[addr - CodeRunner::BaseAddress];
|
||||
}
|
||||
|
||||
void CodeRunner::WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
_byteCode[addr - CodeRunner::BaseAddress] = value;
|
||||
|
||||
if(addr == CodeRunner::BaseAddress) {
|
||||
//Writing to $3000 stops the code runner and resumes normal execution
|
||||
_debugger->StopCodeRunner();
|
||||
_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<DisassemblyInfo> CodeRunner::GetDisassemblyInfo(uint16_t cpuAddress)
|
||||
{
|
||||
return shared_ptr<DisassemblyInfo>(new DisassemblyInfo(_byteCode.data() + cpuAddress - CodeRunner::BaseAddress, false));
|
||||
}
|
26
Core/CodeRunner.h
Normal file
26
Core/CodeRunner.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
|
||||
class Debugger;
|
||||
class DisassemblyInfo;
|
||||
|
||||
class CodeRunner : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
vector<uint8_t> _byteCode;
|
||||
Debugger *_debugger;
|
||||
bool _running;
|
||||
|
||||
public:
|
||||
static const uint16_t BaseAddress = 0x3000;
|
||||
|
||||
CodeRunner(vector<uint8_t> byteCode, Debugger *debugger);
|
||||
|
||||
bool IsRunning();
|
||||
shared_ptr<DisassemblyInfo> GetDisassemblyInfo(uint16_t cpuAddress);
|
||||
|
||||
void GetMemoryRanges(MemoryRanges &ranges) override;
|
||||
uint8_t ReadRAM(uint16_t addr) override;
|
||||
void WriteRAM(uint16_t addr, uint8_t value) override;
|
||||
};
|
|
@ -440,6 +440,7 @@
|
|||
<ClInclude Include="Bs5.h" />
|
||||
<ClInclude Include="Caltron41.h" />
|
||||
<ClInclude Include="Cc21.h" />
|
||||
<ClInclude Include="CodeRunner.h" />
|
||||
<ClInclude Include="ColorDreams46.h" />
|
||||
<ClInclude Include="CpuState.h" />
|
||||
<ClInclude Include="CrossFeedFilter.h" />
|
||||
|
@ -764,6 +765,7 @@
|
|||
<ClCompile Include="Breakpoint.cpp" />
|
||||
<ClCompile Include="CheatManager.cpp" />
|
||||
<ClCompile Include="CodeDataLogger.cpp" />
|
||||
<ClCompile Include="CodeRunner.cpp" />
|
||||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="ControlManager.cpp" />
|
||||
<ClCompile Include="CrossFeedFilter.cpp" />
|
||||
|
|
|
@ -1126,6 +1126,9 @@
|
|||
<ClInclude Include="Assembler.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CodeRunner.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1323,5 +1326,8 @@
|
|||
<ClCompile Include="Assembler.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CodeRunner.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -15,6 +15,8 @@
|
|||
#include "MemoryAccessCounter.h"
|
||||
#include "Profiler.h"
|
||||
#include "Assembler.h"
|
||||
#include "CodeRunner.h"
|
||||
#include "DisassemblyInfo.h"
|
||||
|
||||
Debugger* Debugger::Instance = nullptr;
|
||||
const int Debugger::BreakpointTypeCount;
|
||||
|
@ -51,6 +53,8 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
|
||||
_currentReadAddr = nullptr;
|
||||
_currentReadValue = nullptr;
|
||||
_nextReadAddr = -1;
|
||||
_returnToAddress = 0;
|
||||
|
||||
_ppuScrollX = 0;
|
||||
_ppuScrollY = 0;
|
||||
|
@ -338,6 +342,18 @@ void Debugger::PrivateProcessPpuCycle()
|
|||
|
||||
bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value)
|
||||
{
|
||||
if(type == MemoryOperationType::ExecOpCode && _nextReadAddr != -1) {
|
||||
//SetNextStatement (either from manual action or code runner)
|
||||
if(addr < 0x3000 || addr >= 0x4000) {
|
||||
_returnToAddress = addr;
|
||||
}
|
||||
|
||||
addr = _nextReadAddr;
|
||||
value = _memoryManager->DebugRead(addr, false);
|
||||
_cpu->SetDebugPC(addr);
|
||||
_nextReadAddr = -1;
|
||||
}
|
||||
|
||||
_currentReadAddr = &addr;
|
||||
_currentReadValue = &value;
|
||||
|
||||
|
@ -389,8 +405,19 @@ bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
|
|||
|
||||
breakDone = SleepUntilResume();
|
||||
|
||||
if(_codeRunner && !_codeRunner->IsRunning()) {
|
||||
_codeRunner.reset();
|
||||
}
|
||||
|
||||
GetState(&_debugState, false);
|
||||
_traceLogger->Log(_debugState.CPU, _debugState.PPU, _disassembler->GetDisassemblyInfo(absoluteAddr, absoluteRamAddr, addr));
|
||||
|
||||
shared_ptr<DisassemblyInfo> disassemblyInfo;
|
||||
if(_codeRunner && _codeRunner->IsRunning() && addr >= 0x3000 && addr < 0x4000) {
|
||||
disassemblyInfo = _codeRunner->GetDisassemblyInfo(addr);
|
||||
} else {
|
||||
disassemblyInfo = _disassembler->GetDisassemblyInfo(absoluteAddr, absoluteRamAddr, addr);
|
||||
}
|
||||
_traceLogger->Log(_debugState.CPU, _debugState.PPU, disassemblyInfo);
|
||||
|
||||
_lastInstruction = value;
|
||||
} else {
|
||||
|
@ -412,6 +439,7 @@ bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
|
|||
}
|
||||
|
||||
_currentReadAddr = nullptr;
|
||||
_currentReadValue = nullptr;
|
||||
|
||||
if(type == MemoryOperationType::Write) {
|
||||
if(_frozenAddresses[addr]) {
|
||||
|
@ -617,7 +645,11 @@ void Debugger::SetNextStatement(uint16_t addr)
|
|||
if(_currentReadAddr) {
|
||||
_cpu->SetDebugPC(addr);
|
||||
*_currentReadAddr = addr;
|
||||
*_currentReadValue = _memoryManager->DebugRead(addr);
|
||||
*_currentReadValue = _memoryManager->DebugRead(addr, false);
|
||||
} else {
|
||||
//Can't change the address right away (CPU is in the middle of an instruction)
|
||||
//Address will change after current instruction is done executing
|
||||
_nextReadAddr = addr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,6 +803,24 @@ void Debugger::GetFreezeState(uint16_t startAddress, uint16_t length, bool* free
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::StartCodeRunner(uint8_t *byteCode, uint32_t codeLength)
|
||||
{
|
||||
_codeRunner.reset(new CodeRunner(vector<uint8_t>(byteCode, byteCode + codeLength), this));
|
||||
_memoryManager->RegisterIODevice(_codeRunner.get());
|
||||
_returnToAddress = _cpu->GetState().DebugPC;
|
||||
SetNextStatement(CodeRunner::BaseAddress);
|
||||
}
|
||||
|
||||
void Debugger::StopCodeRunner()
|
||||
{
|
||||
_memoryManager->UnregisterIODevice(_codeRunner.get());
|
||||
_memoryManager->RegisterIODevice(_ppu.get());
|
||||
|
||||
//Break debugger when code has finished executing
|
||||
SetNextStatement(_returnToAddress);
|
||||
Debugger::Instance->Step(1);
|
||||
}
|
||||
|
||||
void Debugger::SaveRomToDisk(string filename)
|
||||
{
|
||||
_mapper->SaveRomToDisk(filename);
|
||||
|
|
|
@ -25,6 +25,7 @@ class LabelManager;
|
|||
class MemoryDumper;
|
||||
class MemoryAccessCounter;
|
||||
class Profiler;
|
||||
class CodeRunner;
|
||||
|
||||
class Debugger
|
||||
{
|
||||
|
@ -41,6 +42,7 @@ private:
|
|||
shared_ptr<LabelManager> _labelManager;
|
||||
shared_ptr<TraceLogger> _traceLogger;
|
||||
shared_ptr<Profiler> _profiler;
|
||||
unique_ptr<CodeRunner> _codeRunner;
|
||||
|
||||
shared_ptr<Console> _console;
|
||||
shared_ptr<CPU> _cpu;
|
||||
|
@ -75,6 +77,8 @@ private:
|
|||
//Used to alter the executing address via "Set Next Statement"
|
||||
uint16_t *_currentReadAddr;
|
||||
uint8_t *_currentReadValue;
|
||||
int32_t _nextReadAddr;
|
||||
uint16_t _returnToAddress;
|
||||
|
||||
uint32_t _flags;
|
||||
|
||||
|
@ -181,6 +185,9 @@ public:
|
|||
void SetFreezeState(uint16_t address, bool frozen);
|
||||
void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState);
|
||||
|
||||
void StartCodeRunner(uint8_t *byteCode, uint32_t codeLength);
|
||||
void StopCodeRunner();
|
||||
|
||||
void SaveRomToDisk(string filename);
|
||||
|
||||
int32_t FindSubEntryPoint(uint16_t relativeAddress);
|
||||
|
|
|
@ -31,7 +31,7 @@ static const char* hexTable[256] = {
|
|||
void DisassemblyInfo::ToString(string &out, uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager)
|
||||
{
|
||||
char buffer[500];
|
||||
uint8_t opCode = *_opPointer;
|
||||
uint8_t opCode = _byteCode[0];
|
||||
uint16_t length = (uint16_t)DisassemblyInfo::OPName[opCode].size();
|
||||
|
||||
memcpy(buffer, DisassemblyInfo::OPName[opCode].c_str(), length);
|
||||
|
@ -118,9 +118,9 @@ uint16_t DisassemblyInfo::GetOpAddr(uint16_t memoryAddr)
|
|||
{
|
||||
uint16_t opAddr = 0;
|
||||
if(_opSize == 2) {
|
||||
opAddr = *(_opPointer + 1);
|
||||
opAddr = _byteCode[1];
|
||||
} else if(_opSize == 3) {
|
||||
opAddr = *(_opPointer + 1) | (*(_opPointer + 2) << 8);
|
||||
opAddr = _byteCode[1] | (_byteCode[2] << 8);
|
||||
}
|
||||
|
||||
if(_opMode == AddrMode::Rel) {
|
||||
|
@ -132,12 +132,16 @@ uint16_t DisassemblyInfo::GetOpAddr(uint16_t memoryAddr)
|
|||
|
||||
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
|
||||
{
|
||||
_opPointer = opPointer;
|
||||
_isSubEntryPoint = isSubEntryPoint;
|
||||
|
||||
uint8_t opCode = *_opPointer;
|
||||
uint8_t opCode = *opPointer;
|
||||
_opSize = DisassemblyInfo::OPSize[opCode];
|
||||
_opMode = DisassemblyInfo::OPMode[opCode];
|
||||
|
||||
for(uint32_t i = 0; i < _opSize; i++) {
|
||||
_byteCode[i] = *(opPointer + i);
|
||||
}
|
||||
|
||||
_isSubExitPoint = opCode == 0x40 || opCode == 0x60;
|
||||
}
|
||||
|
||||
|
@ -191,34 +195,34 @@ void DisassemblyInfo::GetEffectiveAddressString(string &out, State& cpuState, Me
|
|||
int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* memoryManager)
|
||||
{
|
||||
switch(_opMode) {
|
||||
case AddrMode::ZeroX: return (uint8_t)(*(_opPointer + 1) + cpuState.X); break;
|
||||
case AddrMode::ZeroY: return (uint8_t)(*(_opPointer + 1) + cpuState.Y); break;
|
||||
case AddrMode::ZeroX: return (uint8_t)(_byteCode[1] + cpuState.X); break;
|
||||
case AddrMode::ZeroY: return (uint8_t)(_byteCode[1] + cpuState.Y); break;
|
||||
|
||||
case AddrMode::IndX: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1) + cpuState.X;
|
||||
uint8_t zeroAddr = _byteCode[1] + cpuState.X;
|
||||
return memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
}
|
||||
|
||||
case AddrMode::IndY:
|
||||
case AddrMode::IndYW: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1);
|
||||
uint8_t zeroAddr = _byteCode[1];
|
||||
uint16_t addr = memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
return (uint16_t)(addr + cpuState.Y);
|
||||
}
|
||||
|
||||
case AddrMode::Ind: {
|
||||
uint8_t zeroAddr = *(_opPointer + 1);
|
||||
uint8_t zeroAddr = _byteCode[1];
|
||||
return memoryManager->DebugRead(zeroAddr) | memoryManager->DebugRead((uint8_t)(zeroAddr + 1)) << 8;
|
||||
}
|
||||
|
||||
case AddrMode::AbsX:
|
||||
case AddrMode::AbsXW: {
|
||||
return (uint16_t)((*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.X) & 0xFFFF;
|
||||
return (uint16_t)((_byteCode[1] | (_byteCode[2] << 8)) + cpuState.X) & 0xFFFF;
|
||||
}
|
||||
|
||||
case AddrMode::AbsY:
|
||||
case AddrMode::AbsYW: {
|
||||
return (uint16_t)((*(_opPointer + 1) | (*(_opPointer + 2) << 8)) + cpuState.Y) & 0xFFFF;
|
||||
return (uint16_t)((_byteCode[1] | (_byteCode[2] << 8)) + cpuState.Y) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,8 +241,8 @@ void DisassemblyInfo::GetByteCode(string &out)
|
|||
byteCode[pos++] = '$';
|
||||
}
|
||||
|
||||
byteCode[pos++] = hexTable[(uint8_t)*(_opPointer + i)][0];
|
||||
byteCode[pos++] = hexTable[(uint8_t)*(_opPointer + i)][1];
|
||||
byteCode[pos++] = hexTable[_byteCode[i]][0];
|
||||
byteCode[pos++] = hexTable[_byteCode[i]][1];
|
||||
}
|
||||
|
||||
byteCode[pos] = 0;
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
static bool IsUnofficialCode[256];
|
||||
|
||||
private:
|
||||
uint8_t *_opPointer = nullptr;
|
||||
uint8_t _byteCode[3];
|
||||
bool _isSubEntryPoint = false;
|
||||
bool _isSubExitPoint = false;
|
||||
uint32_t _opSize = 0;
|
||||
|
|
|
@ -46,15 +46,16 @@ class MemoryRanges
|
|||
end = start;
|
||||
}
|
||||
|
||||
vector<uint16_t> *addresses;
|
||||
if(operation == MemoryOperation::Read) {
|
||||
addresses = &_ramReadAddresses;
|
||||
} else {
|
||||
addresses = &_ramWriteAddresses;
|
||||
if(operation == MemoryOperation::Read || operation == MemoryOperation::Any) {
|
||||
for(uint32_t i = start; i <= end; i++) {
|
||||
_ramReadAddresses.push_back((uint16_t)i);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = start; i <= end; i++) {
|
||||
addresses->push_back((uint16_t)i);
|
||||
|
||||
if(operation == MemoryOperation::Write || operation == MemoryOperation::Any) {
|
||||
for(uint32_t i = start; i <= end; i++) {
|
||||
_ramWriteAddresses.push_back((uint16_t)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,7 +66,7 @@ void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
|||
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses, bool allowOverride)
|
||||
{
|
||||
for(uint16_t address : *addresses) {
|
||||
if(!allowOverride && memoryHandlers[address] != nullptr) {
|
||||
if(!allowOverride && memoryHandlers[address] != nullptr && memoryHandlers[address] != handler) {
|
||||
throw std::runtime_error("Not supported");
|
||||
}
|
||||
memoryHandlers[address] = handler;
|
||||
|
@ -82,17 +82,31 @@ void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
|
|||
InitializeMemoryHandlers(_ramWriteHandlers, handler, ranges.GetRAMWriteAddresses(), ranges.GetAllowOverride());
|
||||
}
|
||||
|
||||
void MemoryManager::UnregisterIODevice(IMemoryHandler *handler)
|
||||
{
|
||||
MemoryRanges ranges;
|
||||
handler->GetMemoryRanges(ranges);
|
||||
|
||||
for(uint16_t address : *ranges.GetRAMReadAddresses()) {
|
||||
_ramReadHandlers[address] = nullptr;
|
||||
}
|
||||
|
||||
for(uint16_t address : *ranges.GetRAMWriteAddresses()) {
|
||||
_ramWriteHandlers[address] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* MemoryManager::GetInternalRAM()
|
||||
{
|
||||
return _internalRAM;
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::DebugRead(uint16_t addr)
|
||||
uint8_t MemoryManager::DebugRead(uint16_t addr, bool disableRegisterReads)
|
||||
{
|
||||
uint8_t value = 0x00;
|
||||
if(addr <= 0x1FFF) {
|
||||
value = _internalRAM[addr & 0x07FF];
|
||||
} else if(addr > 0x4017) {
|
||||
} else if(!disableRegisterReads || addr > 0x4017) {
|
||||
value = ReadRegister(addr);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,9 @@ class MemoryManager: public Snapshotable
|
|||
|
||||
void Reset(bool softReset);
|
||||
void RegisterIODevice(IMemoryHandler *handler);
|
||||
void UnregisterIODevice(IMemoryHandler *handler);
|
||||
|
||||
uint8_t DebugRead(uint16_t addr);
|
||||
uint8_t DebugRead(uint16_t addr, bool disableRegisterReads = true);
|
||||
uint16_t DebugReadWord(uint16_t addr);
|
||||
uint8_t DebugReadVRAM(uint16_t addr);
|
||||
void DebugWrite(uint16_t addr, uint8_t value);
|
||||
|
|
104
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
104
GUI.NET/Debugger/frmAssembler.Designer.cs
generated
|
@ -30,10 +30,10 @@
|
|||
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.btnExecute = new System.Windows.Forms.Button();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.txtStartAddress = new System.Windows.Forms.TextBox();
|
||||
|
@ -44,13 +44,14 @@
|
|||
this.picSizeWarning = new System.Windows.Forms.PictureBox();
|
||||
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblNoChanges = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.txtCode = new Mesen.GUI.Debugger.ZoomlessRichTextBox();
|
||||
this.statCode = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.lblLineNumber = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.ctrlHexBox = new Be.Windows.Forms.HexBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.grpSettings.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
|
@ -59,15 +60,15 @@
|
|||
this.flowLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picSizeWarning)).BeginInit();
|
||||
this.flowLayoutPanel3.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.statCode.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.Location = new System.Drawing.Point(279, 3);
|
||||
this.btnOk.Location = new System.Drawing.Point(186, 3);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 0;
|
||||
|
@ -79,7 +80,7 @@
|
|||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(360, 3);
|
||||
this.btnCancel.Location = new System.Drawing.Point(267, 3);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
|
@ -105,23 +106,6 @@
|
|||
this.tableLayoutPanel1.Size = new System.Drawing.Size(835, 557);
|
||||
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(3, 16);
|
||||
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(438, 391);
|
||||
this.ctrlHexBox.TabIndex = 1;
|
||||
this.ctrlHexBox.UseFixedBytesPerLine = true;
|
||||
this.ctrlHexBox.VScrollBarVisible = true;
|
||||
//
|
||||
// lstErrors
|
||||
//
|
||||
this.lstErrors.FormattingEnabled = true;
|
||||
|
@ -144,23 +128,40 @@
|
|||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 1;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.ColumnCount = 2;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 21.23288F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 78.76712F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.btnExecute, 0, 3);
|
||||
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.Controls.Add(this.flowLayoutPanel3, 1, 3);
|
||||
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.RowCount = 4;
|
||||
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.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(438, 116);
|
||||
this.tableLayoutPanel2.TabIndex = 0;
|
||||
//
|
||||
// btnExecute
|
||||
//
|
||||
this.btnExecute.Image = global::Mesen.GUI.Properties.Resources.Play;
|
||||
this.btnExecute.Location = new System.Drawing.Point(3, 89);
|
||||
this.btnExecute.Name = "btnExecute";
|
||||
this.btnExecute.Size = new System.Drawing.Size(87, 23);
|
||||
this.btnExecute.TabIndex = 6;
|
||||
this.btnExecute.Text = "Execute";
|
||||
this.btnExecute.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.btnExecute.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
|
||||
this.btnExecute.UseVisualStyleBackColor = true;
|
||||
this.btnExecute.Click += new System.EventHandler(this.btnExecute_Click);
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.flowLayoutPanel1, 2);
|
||||
this.flowLayoutPanel1.Controls.Add(this.label1);
|
||||
this.flowLayoutPanel1.Controls.Add(this.txtStartAddress);
|
||||
this.flowLayoutPanel1.Controls.Add(this.picStartAddressWarning);
|
||||
|
@ -206,6 +207,7 @@
|
|||
//
|
||||
// flowLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.flowLayoutPanel2, 2);
|
||||
this.flowLayoutPanel2.Controls.Add(this.label2);
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblByteUsage);
|
||||
this.flowLayoutPanel2.Controls.Add(this.picSizeWarning);
|
||||
|
@ -254,10 +256,10 @@
|
|||
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.Location = new System.Drawing.Point(93, 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.Size = new System.Drawing.Size(345, 30);
|
||||
this.flowLayoutPanel3.TabIndex = 5;
|
||||
//
|
||||
// lblNoChanges
|
||||
|
@ -266,12 +268,23 @@
|
|||
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.Location = new System.Drawing.Point(6, 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";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.panel1);
|
||||
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox1.Location = new System.Drawing.Point(3, 3);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(379, 410);
|
||||
this.groupBox1.TabIndex = 4;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Code Editor";
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
|
||||
|
@ -331,17 +344,6 @@
|
|||
this.lblLineNumber.Size = new System.Drawing.Size(13, 15);
|
||||
this.lblLineNumber.Text = "1";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.panel1);
|
||||
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox1.Location = new System.Drawing.Point(3, 3);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(379, 410);
|
||||
this.groupBox1.TabIndex = 4;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Code Editor";
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.ctrlHexBox);
|
||||
|
@ -353,6 +355,23 @@
|
|||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Assembled Byte Code";
|
||||
//
|
||||
// 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(3, 16);
|
||||
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(438, 391);
|
||||
this.ctrlHexBox.TabIndex = 1;
|
||||
this.ctrlHexBox.UseFixedBytesPerLine = true;
|
||||
this.ctrlHexBox.VScrollBarVisible = true;
|
||||
//
|
||||
// frmAssembler
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -360,7 +379,7 @@
|
|||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(835, 557);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.MinimumSize = new System.Drawing.Size(813, 502);
|
||||
this.MinimumSize = new System.Drawing.Size(851, 502);
|
||||
this.Name = "frmAssembler";
|
||||
this.Text = "Assembler";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
|
@ -374,11 +393,11 @@
|
|||
((System.ComponentModel.ISupportInitialize)(this.picSizeWarning)).EndInit();
|
||||
this.flowLayoutPanel3.ResumeLayout(false);
|
||||
this.flowLayoutPanel3.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.statCode.ResumeLayout(false);
|
||||
this.statCode.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
|
@ -409,5 +428,6 @@
|
|||
private System.Windows.Forms.PictureBox picStartAddressWarning;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.Button btnExecute;
|
||||
}
|
||||
}
|
|
@ -144,6 +144,8 @@ namespace Mesen.GUI.Debugger
|
|||
lblByteUsage.Text = ctrlHexBox.ByteProvider.Length.ToString();
|
||||
}
|
||||
|
||||
btnExecute.Enabled = ctrlHexBox.ByteProvider.Length > 0 && ctrlHexBox.ByteProvider.Length <= 4000;
|
||||
|
||||
picStartAddressWarning.Visible = !_startAddressValid;
|
||||
}
|
||||
|
||||
|
@ -176,8 +178,39 @@ namespace Mesen.GUI.Debugger
|
|||
UpdateWindow();
|
||||
}
|
||||
|
||||
private void btnExecute_Click(object sender, EventArgs e)
|
||||
{
|
||||
WaitUntilBreak();
|
||||
|
||||
List<string> warningMessages = new List<string>();
|
||||
if(_hasParsingErrors) {
|
||||
warningMessages.Add("Warning: The code contains parsing errors - lines with errors will be ignored.");
|
||||
}
|
||||
warningMessages.Add("Warning: The CPU will not resume its normal execution until a write to $3000 is performed (or the last line of code is reached)!");
|
||||
warningMessages.Add("This will assemble and execute the code in the $3000-$3FFF range, starting at address $3000." + Environment.NewLine + Environment.NewLine + "Execute?");
|
||||
|
||||
if(MessageBox.Show(string.Join(Environment.NewLine+Environment.NewLine, warningMessages.ToArray()), "Warning", MessageBoxButtons.OKCancel) == DialogResult.OK) {
|
||||
UInt16 originalAddress = _startAddress;
|
||||
_startAddress = 0x3000;
|
||||
UpdateWindow();
|
||||
List<byte> code = ((StaticByteProvider)ctrlHexBox.ByteProvider).Bytes;
|
||||
_startAddress = originalAddress;
|
||||
UpdateWindow();
|
||||
|
||||
//Inject a STA $3000 instruction at the end - not flawless, but will work for typical scenarions
|
||||
code.Add(0x8D);
|
||||
code.Add(0x00);
|
||||
code.Add(0x30);
|
||||
|
||||
InteropEmu.DebugStartCodeRunner(code.ToArray());
|
||||
InteropEmu.DebugRun();
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
WaitUntilBreak();
|
||||
|
||||
List<string> warningMessages = new List<string>();
|
||||
if(_hasParsingErrors) {
|
||||
warningMessages.Add("Warning: The code contains parsing errors - lines with errors will be ignored.");
|
||||
|
@ -213,6 +246,14 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
|
||||
private void WaitUntilBreak()
|
||||
{
|
||||
while(!InteropEmu.DebugIsExecutionStopped()) {
|
||||
InteropEmu.DebugStep(1);
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
|
|
|
@ -123,4 +123,7 @@
|
|||
<metadata name="statCode.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>107, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statCode.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>107, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -189,6 +189,17 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern Byte DebugGetMemoryValue(DebugMemoryType type, UInt32 address);
|
||||
[DllImport(DLLPath)] public static extern void DebugSetMemoryValue(DebugMemoryType type, UInt32 address, byte value);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugStartCodeRunner")] private static extern void DebugStartCodeRunnerWrapper(IntPtr byteCode, Int32 codeLength);
|
||||
public static void DebugStartCodeRunner(byte[] data)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
try {
|
||||
InteropEmu.DebugStartCodeRunnerWrapper(handle.AddrOfPinnedObject(), data.Length);
|
||||
} finally {
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugSetMemoryValues")] private static extern void DebugSetMemoryValuesWrapper(DebugMemoryType type, UInt32 address, IntPtr data, Int32 length);
|
||||
public static void DebugSetMemoryValues(DebugMemoryType type, UInt32 address, byte[] data)
|
||||
{
|
||||
|
|
|
@ -98,6 +98,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 DebugStartCodeRunner(uint8_t* byteCode, uint32_t codeLength) { return GetDebugger()->StartCodeRunner(byteCode, codeLength); }
|
||||
|
||||
DllExport void __stdcall DebugSaveRomToDisk(char* filename) { GetDebugger()->SaveRomToDisk(filename); }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue