Debugger: Added DSP registers to register viewer

+ Track DSP reads/writes for debug tools (e.g breakpoints, hex editor highlights, etc.)
This commit is contained in:
Sour 2020-02-10 00:12:00 -05:00
parent d5c4204bb3
commit c385155955
11 changed files with 165 additions and 26 deletions

View file

@ -15,7 +15,8 @@ struct DebugState
CpuState Cpu;
PpuState Ppu;
SpcState Spc;
NecDspState Dsp;
DspState Dsp;
NecDspState NecDsp;
CpuState Sa1;
GsuState Gsu;
Cx4State Cx4;

View file

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

View file

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

View file

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

View file

@ -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<CpuType::Spc>(addr, value, MemoryOperationType::Read);
#endif
return value;
}
void Spc::DspWriteRam(uint16_t addr, uint8_t value)
{
#ifndef DUMMYSPC
_console->ProcessMemoryWrite<CpuType::Spc>(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();

View file

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

View file

@ -31,6 +31,11 @@ struct SpcState
SpcTimer<16> Timer2;
};
struct DspState
{
uint8_t Regs[128];
};
namespace SpcFlags {
enum SpcFlags : uint8_t
{

View file

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

View file

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

View file

@ -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<RegEntry> entries = new List<RegEntry>();
Action<int, string> 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;

View file

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