From c3851559555dc2431c795288db21977c8001a4db Mon Sep 17 00:00:00 2001 From: Sour Date: Mon, 10 Feb 2020 00:12:00 -0500 Subject: [PATCH] Debugger: Added DSP registers to register viewer + Track DSP reads/writes for debug tools (e.g breakpoints, hex editor highlights, etc.) --- Core/DebugTypes.h | 3 +- Core/Debugger.cpp | 3 +- Core/SPC_DSP.cpp | 31 +++++++---- Core/SPC_DSP.h | 9 ++-- Core/Spc.cpp | 34 ++++++++++++- Core/Spc.h | 5 ++ Core/SpcTypes.h | 5 ++ Core/TraceLogger.cpp | 4 +- .../PpuViewer/frmRegisterViewer.Designer.cs | 39 +++++++++++--- UI/Debugger/PpuViewer/frmRegisterViewer.cs | 51 +++++++++++++++++++ UI/Interop/DebugState.cs | 7 +++ 11 files changed, 165 insertions(+), 26 deletions(-) diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index c82aed8..dc2a6f5 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -15,7 +15,8 @@ struct DebugState CpuState Cpu; PpuState Ppu; SpcState Spc; - NecDspState Dsp; + DspState Dsp; + NecDspState NecDsp; CpuState Sa1; GsuState Gsu; Cx4State Cx4; diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 5662772..14c59d5 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -412,6 +412,7 @@ void Debugger::GetState(DebugState &state, bool partialPpuState) state.Cpu = _cpu->GetState(); _ppu->GetState(state.Ppu, partialPpuState); state.Spc = _spc->GetState(); + state.Dsp = _spc->GetDspState(); if(!partialPpuState) { for(int i = 0; i < 8; i++) { @@ -422,7 +423,7 @@ void Debugger::GetState(DebugState &state, bool partialPpuState) } if(_cart->GetDsp()) { - state.Dsp = _cart->GetDsp()->GetState(); + state.NecDsp = _cart->GetDsp()->GetState(); } if(_cart->GetSa1()) { state.Sa1 = _cart->GetSa1()->GetCpuState(); diff --git a/Core/SPC_DSP.cpp b/Core/SPC_DSP.cpp index 6fb5d7c..5a2ed97 100644 --- a/Core/SPC_DSP.cpp +++ b/Core/SPC_DSP.cpp @@ -19,6 +19,7 @@ License along with this module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" +#include "Spc.h" #ifdef BLARGG_ENABLE_OPTIMIZER #include BLARGG_ENABLE_OPTIMIZER @@ -292,7 +293,7 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) inline void SPC_DSP::decode_brr( voice_t* v ) { // Arrange the four input nybbles in 0xABCD order for easy decoding - int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + int nybbles = m.t_brr_byte * 0x100 + readRam(v->brr_addr + v->brr_offset + 1); int const header = m.t_brr_header; @@ -397,10 +398,10 @@ inline VOICE_CLOCK( V1 ) inline VOICE_CLOCK( V2 ) { // Read sample pointer (ignored if not needed) - uint8_t const* entry = &m.ram [m.t_dir_addr]; + uint16_t entry = m.t_dir_addr; if ( !v->kon_delay ) entry += 2; - m.t_brr_next_addr = GET_LE16A( entry ); + m.t_brr_next_addr = readRam(entry) | (readRam(entry+1) << 8); m.t_adsr0 = VREG(v->regs,adsr0); @@ -414,8 +415,8 @@ inline VOICE_CLOCK( V3a ) inline VOICE_CLOCK( V3b ) { // Read BRR header and byte - m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; - m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking + m.t_brr_byte = readRam(v->brr_addr + v->brr_offset); + m.t_brr_header = readRam(v->brr_addr); // brr_addr doesn't need masking } VOICE_CLOCK( V3c ) { @@ -588,7 +589,7 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } //// Echo // Current echo buffer pointer for left/right channel -#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) +#define ECHO_PTR( ch ) (m.t_echo_ptr + ch * 2) // Sample in echo history buffer, where 0 is the oldest #define ECHO_FIR( i ) (m.echo_hist_pos [i]) @@ -600,7 +601,8 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } inline void SPC_DSP::echo_read( int ch ) { - int s = GET_LE16SA( ECHO_PTR( ch ) ); + uint16_t echoPtr = ECHO_PTR(ch); + int16_t s = readRam(echoPtr) | (readRam(echoPtr+1) << 8); // second copy simplifies wrap-around handling ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; } @@ -711,7 +713,9 @@ ECHO_CLOCK( 28 ) inline void SPC_DSP::echo_write( int ch ) { if(!(m.t_echo_enabled & 0x20)) { - SET_LE16A(ECHO_PTR(ch), m.t_echo_out[ch]); + uint16_t echoPtr = ECHO_PTR(ch); + writeRam(echoPtr, m.t_echo_out[ch]); + writeRam(echoPtr+1, m.t_echo_out[ch] >> 8); } m.t_echo_out [ch] = 0; } @@ -790,8 +794,9 @@ PHASE(31) V(V4,0) V(V1,2)\ void SPC_DSP::run() { - m.phase = (m.phase + 1) & 31; - switch (m.phase) + int const phase = m.phase; + m.phase = (phase + 1) & 31; + switch (phase) { #define PHASE( n ) if ( n ) break; case n: GEN_DSP_TIMING @@ -799,13 +804,17 @@ void SPC_DSP::run() } } +inline uint8_t SPC_DSP::readRam(uint16_t addr) { return _spc->DspReadRam(addr); } +inline void SPC_DSP::writeRam(uint16_t addr, uint8_t value) { _spc->DspWriteRam(addr, value); } + #endif //// Setup -void SPC_DSP::init( void* ram_64k ) +void SPC_DSP::init( Spc *spc, void* ram_64k ) { + _spc = spc; m.ram = (uint8_t*) ram_64k; mute_voices( 0 ); disable_surround( false ); diff --git a/Core/SPC_DSP.h b/Core/SPC_DSP.h index f97f938..5ab3b28 100644 --- a/Core/SPC_DSP.h +++ b/Core/SPC_DSP.h @@ -5,9 +5,9 @@ #define SPC_DSP_H #include "blargg_common.h" - extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } +class Spc; class SPC_DSP { public: typedef BOOST::uint8_t uint8_t; @@ -15,7 +15,7 @@ public: // Setup // Initializes DSP and has it use the 64K RAM provided - void init( void* ram_64k ); + void init( Spc* spc, void* ram_64k ); // Sets destination for output samples. If out is NULL or out_size is 0, // doesn't generate any. @@ -45,7 +45,9 @@ public: void run(); bool isMuted() { return (m.regs[r_flg] & 0x40) != 0; } - + void copyRegs(uint8_t* output) { memcpy(output, m.regs, register_count); } + uint8_t readRam(uint16_t addr); + void writeRam(uint16_t addr, uint8_t value); // Sound control // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). @@ -188,6 +190,7 @@ private: sample_t extra [extra_size]; }; state_t m; + Spc* _spc; void init_counter(); void run_counters(); diff --git a/Core/Spc.cpp b/Core/Spc.cpp index 58339be..3000ec0 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -5,7 +5,13 @@ #include "SoundMixer.h" #include "EmuSettings.h" #include "SpcFileData.h" +#ifndef DUMMYSPC #include "SPC_DSP.h" +#else +#undef Spc +#include "SPC_DSP.h" +#define Spc DummySpc +#endif #include "../Utilities/Serializer.h" Spc::Spc(Console* console) @@ -18,7 +24,9 @@ Spc::Spc(Console* console) _console->GetSettings()->InitializeRam(_ram, Spc::SpcRamSize); _dsp.reset(new SPC_DSP()); - _dsp->init(_ram); + #ifndef DUMMYSPC + _dsp->init(this, _ram); + #endif _dsp->reset(); _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); @@ -306,6 +314,23 @@ void Spc::CpuWriteRegister(uint32_t addr, uint8_t value) _state.CpuRegs[addr & 0x03] = value; } +uint8_t Spc::DspReadRam(uint16_t addr) +{ + uint8_t value = _ram[addr]; +#ifndef DUMMYSPC + _console->ProcessMemoryRead(addr, value, MemoryOperationType::Read); +#endif + return value; +} + +void Spc::DspWriteRam(uint16_t addr, uint8_t value) +{ +#ifndef DUMMYSPC + _console->ProcessMemoryWrite(addr, value, MemoryOperationType::Write); +#endif + _ram[addr] = value; +} + void Spc::Run() { if(!_enabled || _state.StopState != CpuStopState::Running) { @@ -348,6 +373,13 @@ SpcState Spc::GetState() return _state; } +DspState Spc::GetDspState() +{ + DspState state; + _dsp->copyRegs(state.Regs); + return state; +} + bool Spc::IsMuted() { return _dsp->isMuted(); diff --git a/Core/Spc.h b/Core/Spc.h index 3437b41..6e01c94 100644 --- a/Core/Spc.h +++ b/Core/Spc.h @@ -295,9 +295,14 @@ public: uint8_t CpuReadRegister(uint16_t addr); void CpuWriteRegister(uint32_t addr, uint8_t value); + uint8_t DspReadRam(uint16_t addr); + void DspWriteRam(uint16_t addr, uint8_t value); + void ProcessEndFrame(); SpcState GetState(); + DspState GetDspState(); + bool IsMuted(); AddressInfo GetAbsoluteAddress(uint16_t addr); int GetRelativeAddress(AddressInfo & absAddress); diff --git a/Core/SpcTypes.h b/Core/SpcTypes.h index ac68ae6..5213f03 100644 --- a/Core/SpcTypes.h +++ b/Core/SpcTypes.h @@ -31,6 +31,11 @@ struct SpcState SpcTimer<16> Timer2; }; +struct DspState +{ + uint8_t Regs[128]; +}; + namespace SpcFlags { enum SpcFlags : uint8_t { diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index de823c4..b4f1f6b 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -491,7 +491,7 @@ void TraceLogger::GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo & switch(cpuType) { case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::CpuMemory); break; case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); break; - case CpuType::NecDsp: GetTraceRow(output, state.Dsp, state.Ppu, disassemblyInfo); break; + case CpuType::NecDsp: GetTraceRow(output, state.NecDsp, state.Ppu, disassemblyInfo); break; case CpuType::Sa1: GetTraceRow(output, state.Sa1, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory); break; case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); break; case CpuType::Cx4: GetTraceRow(output, state.Cx4, state.Ppu, disassemblyInfo); break; @@ -587,7 +587,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) switch(cpuType) { case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((state.Cpu.K << 16) | state.Cpu.PC) + "\x1"; break; case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(state.Spc.PC) + "\x1"; break; - case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.Dsp.PC) + "\x1"; break; + case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.NecDsp.PC) + "\x1"; break; case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Sa1.K << 16) | state.Sa1.PC) + "\x1"; break; case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Gsu.ProgramBank << 16) | state.Gsu.R[15]) + "\x1"; break; case CpuType::Cx4: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Cx4.Cache.Address[state.Cx4.Cache.Page] + (state.Cx4.PC * 2)) & 0xFFFFFF) + "\x1"; break; diff --git a/UI/Debugger/PpuViewer/frmRegisterViewer.Designer.cs b/UI/Debugger/PpuViewer/frmRegisterViewer.Designer.cs index e0b3870..1d51549 100644 --- a/UI/Debugger/PpuViewer/frmRegisterViewer.Designer.cs +++ b/UI/Debugger/PpuViewer/frmRegisterViewer.Designer.cs @@ -44,12 +44,15 @@ this.ctrlPropertyPpu = new Mesen.GUI.Debugger.ctrlPropertyList(); this.tpgSpc = new System.Windows.Forms.TabPage(); this.ctrlPropertySpc = new Mesen.GUI.Debugger.ctrlPropertyList(); + this.tpgDsp = new System.Windows.Forms.TabPage(); + this.ctrlPropertyDsp = new Mesen.GUI.Debugger.ctrlPropertyList(); this.ctrlMesenMenuStrip1.SuspendLayout(); this.tabMain.SuspendLayout(); this.tpgCpu.SuspendLayout(); this.tpgDma.SuspendLayout(); this.tpgPpu.SuspendLayout(); this.tpgSpc.SuspendLayout(); + this.tpgDsp.SuspendLayout(); this.SuspendLayout(); // // ctrlScanlineCycleSelect @@ -125,6 +128,7 @@ this.tabMain.Controls.Add(this.tpgDma); this.tabMain.Controls.Add(this.tpgPpu); this.tabMain.Controls.Add(this.tpgSpc); + this.tabMain.Controls.Add(this.tpgDsp); this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill; this.tabMain.Location = new System.Drawing.Point(0, 24); this.tabMain.Name = "tabMain"; @@ -156,7 +160,7 @@ this.tpgDma.Controls.Add(this.ctrlPropertyDma); this.tpgDma.Location = new System.Drawing.Point(4, 22); this.tpgDma.Name = "tpgDma"; - this.tpgDma.Size = new System.Drawing.Size(526, 461); + this.tpgDma.Size = new System.Drawing.Size(376, 361); this.tpgDma.TabIndex = 2; this.tpgDma.Text = "DMA"; this.tpgDma.UseVisualStyleBackColor = true; @@ -166,7 +170,7 @@ this.ctrlPropertyDma.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlPropertyDma.Location = new System.Drawing.Point(0, 0); this.ctrlPropertyDma.Name = "ctrlPropertyDma"; - this.ctrlPropertyDma.Size = new System.Drawing.Size(526, 461); + this.ctrlPropertyDma.Size = new System.Drawing.Size(376, 361); this.ctrlPropertyDma.TabIndex = 1; // // tpgPpu @@ -174,7 +178,7 @@ this.tpgPpu.Controls.Add(this.ctrlPropertyPpu); this.tpgPpu.Location = new System.Drawing.Point(4, 22); this.tpgPpu.Name = "tpgPpu"; - this.tpgPpu.Size = new System.Drawing.Size(526, 461); + this.tpgPpu.Size = new System.Drawing.Size(376, 361); this.tpgPpu.TabIndex = 1; this.tpgPpu.Text = "PPU"; this.tpgPpu.UseVisualStyleBackColor = true; @@ -184,7 +188,7 @@ this.ctrlPropertyPpu.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlPropertyPpu.Location = new System.Drawing.Point(0, 0); this.ctrlPropertyPpu.Name = "ctrlPropertyPpu"; - this.ctrlPropertyPpu.Size = new System.Drawing.Size(526, 461); + this.ctrlPropertyPpu.Size = new System.Drawing.Size(376, 361); this.ctrlPropertyPpu.TabIndex = 2; // // tpgSpc @@ -192,7 +196,7 @@ this.tpgSpc.Controls.Add(this.ctrlPropertySpc); this.tpgSpc.Location = new System.Drawing.Point(4, 22); this.tpgSpc.Name = "tpgSpc"; - this.tpgSpc.Size = new System.Drawing.Size(526, 461); + this.tpgSpc.Size = new System.Drawing.Size(376, 361); this.tpgSpc.TabIndex = 5; this.tpgSpc.Text = "SPC"; this.tpgSpc.UseVisualStyleBackColor = true; @@ -202,9 +206,27 @@ this.ctrlPropertySpc.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlPropertySpc.Location = new System.Drawing.Point(0, 0); this.ctrlPropertySpc.Name = "ctrlPropertySpc"; - this.ctrlPropertySpc.Size = new System.Drawing.Size(526, 461); + this.ctrlPropertySpc.Size = new System.Drawing.Size(376, 361); this.ctrlPropertySpc.TabIndex = 2; // + // tpgDsp + // + this.tpgDsp.Controls.Add(this.ctrlPropertyDsp); + this.tpgDsp.Location = new System.Drawing.Point(4, 22); + this.tpgDsp.Name = "tpgDsp"; + this.tpgDsp.Size = new System.Drawing.Size(376, 361); + this.tpgDsp.TabIndex = 6; + this.tpgDsp.Text = "DSP"; + this.tpgDsp.UseVisualStyleBackColor = true; + // + // ctrlPropertyDsp + // + this.ctrlPropertyDsp.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlPropertyDsp.Location = new System.Drawing.Point(0, 0); + this.ctrlPropertyDsp.Name = "ctrlPropertyDsp"; + this.ctrlPropertyDsp.Size = new System.Drawing.Size(376, 361); + this.ctrlPropertyDsp.TabIndex = 3; + // // frmRegisterViewer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -225,6 +247,7 @@ this.tpgDma.ResumeLayout(false); this.tpgPpu.ResumeLayout(false); this.tpgSpc.ResumeLayout(false); + this.tpgDsp.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -248,5 +271,7 @@ private ctrlPropertyList ctrlPropertyDma; private ctrlPropertyList ctrlPropertyPpu; private ctrlPropertyList ctrlPropertySpc; - } + private System.Windows.Forms.TabPage tpgDsp; + private ctrlPropertyList ctrlPropertyDsp; + } } \ No newline at end of file diff --git a/UI/Debugger/PpuViewer/frmRegisterViewer.cs b/UI/Debugger/PpuViewer/frmRegisterViewer.cs index 283841c..4e63c21 100644 --- a/UI/Debugger/PpuViewer/frmRegisterViewer.cs +++ b/UI/Debugger/PpuViewer/frmRegisterViewer.cs @@ -218,6 +218,57 @@ namespace Mesen.GUI.Debugger new RegEntry("$FE", "Timer 1 Output", spc.Timer1.Output, Format.X8), new RegEntry("$FF", "Timer 2 Output", spc.Timer2.Output, Format.X8), }); + } else if(tabMain.SelectedTab == tpgDsp) { + DspState dsp = _state.Dsp; + List entries = new List(); + + Action addReg = (int i, string name) => { + entries.Add(new RegEntry("$" + i.ToString("X2"), name, dsp.Regs[i], Format.X8)); + }; + + addReg(0x0C, "Main Volume (MVOL) - Left"); + addReg(0x1C, "Main Volume (MVOL) - Right"); + addReg(0x2C, "Echo Volume (EVOL) - Left"); + addReg(0x3C, "Echo Volume (EVOL) - Right"); + + addReg(0x4C, "Key On (KON)"); + addReg(0x5C, "Key Off (KOF)"); + + addReg(0x7C, "Source End Block (ENDX)"); + addReg(0x0D, "Echo Feedback (EFB)"); + addReg(0x2D, "Pitch Modulation (PMON)"); + addReg(0x3D, "Noise Enable (NON)"); + addReg(0x4D, "Echo Enable (EON)"); + addReg(0x5D, "Source Directory (Offset) (DIR)"); + addReg(0x6D, "Echo Buffer (Offset) (ESA)"); + addReg(0x6D, "Echo Delay (EDL)"); + + entries.Add(new RegEntry("$6C", "Flags (FLG)", null)); + entries.Add(new RegEntry("$6C.0-4", "Noise Clock", dsp.Regs[0x6C] & 0x1F, Format.X8)); + entries.Add(new RegEntry("$6C.5", "Echo Disabled", (dsp.Regs[0x6C] & 0x20) != 0)); + entries.Add(new RegEntry("$6C.6", "Mute", (dsp.Regs[0x6C] & 0x40) != 0)); + entries.Add(new RegEntry("$6C.7", "Reset", (dsp.Regs[0x6C] & 0x80) != 0)); + + entries.Add(new RegEntry("$xF", "Coefficients", null)); + for(int i = 0; i < 8; i++) { + addReg((i << 4) | 0x0F, "Coefficient " + i); + } + + for(int i = 0; i < 8; i++) { + entries.Add(new RegEntry("Voice #" + i.ToString(), "", null)); + + int voice = i << 4; + addReg(voice | 0x00, "Left Volume (VOL)"); + addReg(voice | 0x01, "Right Volume (VOL)"); + entries.Add(new RegEntry("$" + i + "2 + $" + i + "3", "Pitch (P)", dsp.Regs[voice | 0x02] | (dsp.Regs[voice | 0x03] << 8), Format.X16)); + addReg(voice | 0x04, "Source (SRCN)"); + addReg(voice | 0x05, "ADSR1"); + addReg(voice | 0x06, "ADSR2"); + addReg(voice | 0x07, "GAIN"); + addReg(voice | 0x08, "ENVX"); + addReg(voice | 0x09, "OUTX"); + } + ctrlPropertyDsp.UpdateState(entries); } else if(tabMain.SelectedTab == tpgPpu) { PpuState ppu = _state.Ppu; diff --git a/UI/Interop/DebugState.cs b/UI/Interop/DebugState.cs index f2d7e92..cf397b8 100644 --- a/UI/Interop/DebugState.cs +++ b/UI/Interop/DebugState.cs @@ -255,6 +255,12 @@ namespace Mesen.GUI public SpcTimer Timer2; }; + public struct DspState + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public byte[] Regs; + } + public struct NecDspAccFlags { [MarshalAs(UnmanagedType.I1)] public bool Carry; @@ -492,6 +498,7 @@ namespace Mesen.GUI public CpuState Cpu; public PpuState Ppu; public SpcState Spc; + public DspState Dsp; public NecDspState NecDsp; public CpuState Sa1; public GsuState Gsu;