Debugger: On-the-fly code running feature via assembler

This commit is contained in:
Souryo 2017-03-11 21:03:45 -05:00
parent e2fb36240d
commit d72a4d8be3
16 changed files with 306 additions and 71 deletions

48
Core/CodeRunner.cpp Normal file
View 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
View 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;
};

View file

@ -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" />

View file

@ -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>

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}
}
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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();

View file

@ -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>

View file

@ -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)
{

View file

@ -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); }