DSP: Added support for DSP-1/2/3/4 games (LLE - requires bios file)

This commit is contained in:
Sour 2019-07-14 21:45:12 -04:00
parent 521df256fa
commit c9405d7ba3
38 changed files with 1325 additions and 72 deletions

View file

@ -4,8 +4,11 @@
#include "RomHandler.h"
#include "MemoryManager.h"
#include "IMemoryHandler.h"
#include "BaseCoprocessor.h"
#include "MessageManager.h"
#include "Console.h"
#include "EmuSettings.h"
#include "NecDsp.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/VirtualFile.h"
#include "../Utilities/FolderUtilities.h"
@ -20,7 +23,7 @@ BaseCartridge::~BaseCartridge()
delete[] _saveRam;
}
shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(EmuSettings* settings, VirtualFile &romFile, VirtualFile &patchFile)
shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile)
{
if(romFile.IsValid()) {
shared_ptr<BaseCartridge> cart(new BaseCartridge());
@ -38,7 +41,7 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(EmuSettings* settings,
return nullptr;
}
cart->_settings = settings;
cart->_console = console;
cart->_romPath = romFile;
cart->_prgRomSize = (uint32_t)romData.size();
cart->_prgRom = new uint8_t[cart->_prgRomSize];
@ -155,16 +158,66 @@ void BaseCartridge::Init()
flags |= CartFlags::FastRom;
}
_flags = (CartFlags::CartFlags)flags;
_coprocessorType = GetCoprocessorType();
_saveRamSize = _cartInfo.SramSize > 0 ? 1024 * (1 << _cartInfo.SramSize) : 0;
_saveRam = new uint8_t[_saveRamSize];
_settings->InitializeRam(_saveRam, _saveRamSize);
_console->GetSettings()->InitializeRam(_saveRam, _saveRamSize);
LoadBattery();
DisplayCartInfo();
}
CoprocessorType BaseCartridge::GetCoprocessorType()
{
if((_cartInfo.RomType & 0x0F) >= 0x03) {
switch((_cartInfo.RomType & 0xF0) >> 4) {
case 0x00: return GetDspVersion(); break;
case 0x01: return CoprocessorType::GSU1; break; //Or mariochip1/gsu2
case 0x02: return CoprocessorType::OBC1; break;
case 0x03: return CoprocessorType::SA1; break;
case 0x04: return CoprocessorType::DD1; break;
case 0x05: return CoprocessorType::RTC; break;
case 0x0E: return CoprocessorType::Satellaview; break;
case 0x0F:
switch(_cartInfo.CartridgeType & 0x0F) {
case 0x00: return CoprocessorType::SPC7110; break;
case 0x01: return CoprocessorType::ST010; break; //or ST011
case 0x02: return CoprocessorType::ST018; break;
case 0x10: return CoprocessorType::CX4; break;
}
break;
}
}
return CoprocessorType::None;
}
CoprocessorType BaseCartridge::GetDspVersion()
{
string cartName = GetCartName();
if(cartName == "DUNGEON MASTER") {
return CoprocessorType::DSP2;
} if(cartName == "PILOTWINGS") {
return CoprocessorType::DSP1;
} else if(cartName == "SD\xB6\xDE\xDD\xC0\xDE\xD1GX") {
//SD Gundam GX
return CoprocessorType::DSP3;
} else if(cartName == "PLANETS CHAMP TG3000" || cartName == "TOP GEAR 3000") {
return CoprocessorType::DSP4;
}
//Default to DSP1B
return CoprocessorType::DSP1B;
}
void BaseCartridge::Reset()
{
_coprocessor->Reset();
}
RomInfo BaseCartridge::GetRomInfo()
{
RomInfo info;
@ -179,6 +232,11 @@ string BaseCartridge::GetSha1Hash()
return SHA1::GetHash(_prgRom, _prgRomSize);
}
CartFlags::CartFlags BaseCartridge::GetCartFlags()
{
return _flags;
}
void BaseCartridge::LoadBattery()
{
if(_saveRamSize > 0) {
@ -298,6 +356,14 @@ void BaseCartridge::RegisterHandlers(MemoryManager &mm)
MapBanks(mm, _saveRamHandlers, 0x70, 0x7D, 0x00, 0x07, 0, true);
MapBanks(mm, _saveRamHandlers, 0xA0, 0xBF, 0x06, 0x07, 0, true);
}
InitCoprocessor(mm);
}
void BaseCartridge::InitCoprocessor(MemoryManager &mm)
{
_coprocessor.reset(NecDsp::InitCoprocessor(_coprocessorType, _console));
_necDsp = dynamic_cast<NecDsp*>(_coprocessor.get());
}
bool BaseCartridge::MapSpecificCarts(MemoryManager &mm)
@ -335,15 +401,26 @@ bool BaseCartridge::MapSpecificCarts(MemoryManager &mm)
void BaseCartridge::Serialize(Serializer &s)
{
s.StreamArray(_saveRam, _saveRamSize);
if(_coprocessor) {
s.Stream(_coprocessor.get());
}
}
string BaseCartridge::GetGameCode()
{
string code;
code += _cartInfo.GameCode[0];
code += _cartInfo.GameCode[1];
code += _cartInfo.GameCode[2];
code += _cartInfo.GameCode[3];
if(_cartInfo.GameCode[0] >= ' ') {
code += _cartInfo.GameCode[0];
}
if(_cartInfo.GameCode[1] >= ' ') {
code += _cartInfo.GameCode[1];
}
if(_cartInfo.GameCode[2] >= ' ') {
code += _cartInfo.GameCode[2];
}
if(_cartInfo.GameCode[3] >= ' ') {
code += _cartInfo.GameCode[3];
}
return code;
}
@ -370,6 +447,10 @@ void BaseCartridge::DisplayCartInfo()
{
MessageManager::Log("-----------------------------");
MessageManager::Log("Game: " + GetCartName());
string gameCode = GetGameCode();
if(!gameCode.empty()) {
MessageManager::Log("Game code: " + gameCode);
}
if(_flags & CartFlags::ExHiRom) {
MessageManager::Log("Type: ExHiROM");
} else if(_flags & CartFlags::ExLoRom) {
@ -380,6 +461,30 @@ void BaseCartridge::DisplayCartInfo()
MessageManager::Log("Type: LoROM");
}
string coProcMessage = "Coprocessor: ";
switch(_coprocessorType) {
case CoprocessorType::None: coProcMessage += "<none>"; break;
case CoprocessorType::CX4: coProcMessage += "CX4"; break;
case CoprocessorType::DD1: coProcMessage += "S-DD1"; break;
case CoprocessorType::DSP1: coProcMessage += "DSP1"; break;
case CoprocessorType::DSP1B: coProcMessage += "DSP1B"; break;
case CoprocessorType::DSP2: coProcMessage += "DSP2"; break;
case CoprocessorType::DSP3: coProcMessage += "DSP3"; break;
case CoprocessorType::DSP4: coProcMessage += "DSP4"; break;
case CoprocessorType::GSU1: coProcMessage += "Super FX (GSU1)"; break;
case CoprocessorType::GSU2: coProcMessage += "Super FX (GSU2)"; break;
case CoprocessorType::MarioChip: coProcMessage += "Super FX (Mario Chip 1)"; break;
case CoprocessorType::OBC1: coProcMessage += "OBC1"; break;
case CoprocessorType::RTC: coProcMessage += "RTC"; break;
case CoprocessorType::SA1: coProcMessage += "SA1"; break;
case CoprocessorType::Satellaview: coProcMessage += "Satellaview"; break;
case CoprocessorType::SPC7110: coProcMessage += "SPC7110"; break;
case CoprocessorType::ST010: coProcMessage += "ST010"; break;
case CoprocessorType::ST011: coProcMessage += "ST011"; break;
case CoprocessorType::ST018: coProcMessage += "ST018"; break;
}
MessageManager::Log(coProcMessage);
if(_flags & CartFlags::FastRom) {
MessageManager::Log("FastROM");
}
@ -397,4 +502,14 @@ void BaseCartridge::DisplayCartInfo()
MessageManager::Log("SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB");
}
MessageManager::Log("-----------------------------");
}
}
NecDsp* BaseCartridge::GetDsp()
{
return _necDsp;
}
BaseCoprocessor * BaseCartridge::GetCoprocessor()
{
return _coprocessor.get();
}

View file

@ -4,34 +4,27 @@
#include "CartTypes.h"
#include "../Utilities/ISerializable.h"
class BaseCoprocessor;
class MemoryManager;
class VirtualFile;
class EmuSettings;
namespace CartFlags
{
enum CartFlags
{
None = 0,
LoRom = 1,
HiRom = 2,
FastRom = 4,
ExLoRom = 8,
ExHiRom = 16,
CopierHeader = 32
};
}
class NecDsp;
class Console;
class BaseCartridge : public ISerializable
{
private:
EmuSettings *_settings;
Console *_console;
vector<unique_ptr<IMemoryHandler>> _prgRomHandlers;
vector<unique_ptr<IMemoryHandler>> _saveRamHandlers;
SnesCartInformation _cartInfo = {};
unique_ptr<BaseCoprocessor> _coprocessor;
NecDsp *_necDsp = nullptr;
CartFlags::CartFlags _flags = CartFlags::CartFlags::None;
CoprocessorType _coprocessorType = CoprocessorType::None;
string _romPath;
string _patchPath;
@ -48,21 +41,28 @@ private:
int32_t GetHeaderScore(uint32_t addr);
void DisplayCartInfo();
CoprocessorType GetCoprocessorType();
CoprocessorType GetDspVersion();
bool MapSpecificCarts(MemoryManager &mm);
void InitCoprocessor(MemoryManager &mm);
string GetCartName();
string GetGameCode();
public:
virtual ~BaseCartridge();
static shared_ptr<BaseCartridge> CreateCartridge(EmuSettings* settings, VirtualFile &romFile, VirtualFile &patchFile);
static shared_ptr<BaseCartridge> CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile);
void Init();
void Reset();
void SaveBattery();
RomInfo GetRomInfo();
string GetSha1Hash();
CartFlags::CartFlags GetCartFlags();
void RegisterHandlers(MemoryManager &mm);
@ -71,5 +71,8 @@ public:
uint32_t DebugGetPrgRomSize() { return _prgRomSize; }
uint32_t DebugGetSaveRamSize() { return _saveRamSize; }
NecDsp* GetDsp();
BaseCoprocessor* GetCoprocessor();
void Serialize(Serializer &s) override;
};

11
Core/BaseCoprocessor.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "stdafx.h"
#include "../Utilities/ISerializable.h"
#include "IMemoryHandler.h"
class BaseCoprocessor : public ISerializable, public IMemoryHandler
{
public:
virtual void Run() = 0;
virtual void Reset() = 0;
};

View file

@ -76,7 +76,7 @@ int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, Addres
CpuType cpuType = category == BreakpointCategory::Spc ? CpuType::Spc : CpuType::Cpu;
DebugState state;
_debugger->GetState(state);
_debugger->GetState(state, false);
EvalResultType resultType;
vector<Breakpoint> &breakpoints = _breakpoints[(int)category][(int)type];
for(size_t i = 0; i < breakpoints.size(); i++) {

View file

@ -30,4 +30,41 @@ struct RomInfo
SnesCartInformation Header;
VirtualFile RomFile;
VirtualFile PatchFile;
};
namespace CartFlags
{
enum CartFlags
{
None = 0,
LoRom = 1,
HiRom = 2,
FastRom = 4,
ExLoRom = 8,
ExHiRom = 16,
CopierHeader = 32
};
}
enum class CoprocessorType
{
None,
DSP1,
DSP1B,
DSP2,
DSP3,
DSP4,
GSU1,
GSU2,
MarioChip,
OBC1,
SA1,
DD1,
RTC,
Satellaview,
SPC7110,
ST010,
ST011,
ST018,
CX4
};

View file

@ -3,6 +3,7 @@
#include "Cpu.h"
#include "Ppu.h"
#include "Spc.h"
#include "NecDsp.h"
#include "InternalRegisters.h"
#include "ControlManager.h"
#include "MemoryManager.h"
@ -96,6 +97,9 @@ void Console::Run()
_cpu->Exec();
if(previousFrameCount != _ppu->GetFrameCount()) {
if(_cart->GetCoprocessor()) {
_cart->GetCoprocessor()->Run();
}
_rewindManager->ProcessEndOfFrame();
WaitForLock();
@ -247,7 +251,7 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom)
_cart->SaveBattery();
}
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(_settings.get(), romFile, patchFile);
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(this, romFile, patchFile);
if(cart) {
if(stopRom) {
Stop(false);
@ -638,11 +642,21 @@ void Console::ProcessWorkRamWrite(uint32_t addr, uint8_t value)
}
}
void Console::ProcessNecDspExec(uint32_t addr, uint32_t value)
{
if(_debugger) {
_debugger->ProcessNecDspExec(addr, value);
}
}
void Console::ProcessPpuCycle()
{
if(_debugger) {
_debugger->ProcessPpuCycle();
_spc->Run();
if(_cart->GetCoprocessor()) {
_cart->GetCoprocessor()->Run();
}
}
}

View file

@ -131,6 +131,7 @@ public:
void ProcessSpcWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessWorkRamRead(uint32_t addr, uint8_t value);
void ProcessWorkRamWrite(uint32_t addr, uint8_t value);
void ProcessNecDspExec(uint32_t addr, uint32_t value);
void ProcessPpuCycle();
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);

View file

@ -47,6 +47,7 @@
<ClInclude Include="AviRecorder.h" />
<ClInclude Include="BaseCartridge.h" />
<ClInclude Include="BaseControlDevice.h" />
<ClInclude Include="BaseCoprocessor.h" />
<ClInclude Include="BaseRenderer.h" />
<ClInclude Include="BaseSoundManager.h" />
<ClInclude Include="BaseVideoFilter.h" />
@ -78,6 +79,9 @@
<ClInclude Include="LuaCallHelper.h" />
<ClInclude Include="LuaScriptingContext.h" />
<ClInclude Include="MemoryAccessCounter.h" />
<ClInclude Include="NecDsp.h" />
<ClInclude Include="NecDspDisUtils.h" />
<ClInclude Include="NecDspTypes.h" />
<ClInclude Include="NtscFilter.h" />
<ClInclude Include="PpuTools.h" />
<ClInclude Include="RegisterHandlerB.h" />
@ -179,6 +183,8 @@
<ClCompile Include="MemoryDumper.cpp" />
<ClCompile Include="MemoryManager.cpp" />
<ClCompile Include="MessageManager.cpp" />
<ClCompile Include="NecDsp.cpp" />
<ClCompile Include="NecDspDisUtils.cpp" />
<ClCompile Include="NotificationManager.cpp" />
<ClCompile Include="NtscFilter.cpp" />
<ClCompile Include="Ppu.cpp" />

View file

@ -290,6 +290,18 @@
<ClInclude Include="AluMulDiv.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="NecDspDisUtils.h">
<Filter>Debugger\Disassembler</Filter>
</ClInclude>
<ClInclude Include="BaseCoprocessor.h">
<Filter>SNES\Coprocessors</Filter>
</ClInclude>
<ClInclude Include="NecDsp.h">
<Filter>SNES\Coprocessors</Filter>
</ClInclude>
<ClInclude Include="NecDspTypes.h">
<Filter>SNES\Coprocessors</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -474,6 +486,10 @@
<Filter>Debugger\Scripts</Filter>
</ClCompile>
<ClCompile Include="AluMulDiv.cpp" />
<ClCompile Include="NecDspDisUtils.cpp" />
<ClCompile Include="NecDsp.cpp">
<Filter>SNES\Coprocessors</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
@ -509,5 +525,8 @@
<Filter Include="Debugger\Scripts">
<UniqueIdentifier>{ca39cd9a-a95c-4b7a-b6d5-de41565dd8f6}</UniqueIdentifier>
</Filter>
<Filter Include="SNES\Coprocessors">
<UniqueIdentifier>{6d4d05d5-3ad3-4087-9be0-3fd9e461c3e0}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -3,6 +3,7 @@
#include "CpuTypes.h"
#include "PpuTypes.h"
#include "SpcTypes.h"
#include "NecDspTypes.h"
struct DebugState
{
@ -10,6 +11,7 @@ struct DebugState
CpuState Cpu;
PpuState Ppu;
SpcState Spc;
NecDspState Dsp;
};
enum class SnesMemoryType
@ -24,6 +26,9 @@ enum class SnesMemoryType
CGRam,
SpcRam,
SpcRom,
DspProgramRom,
DspDataRom,
DspDataRam,
Register,
};
@ -242,6 +247,8 @@ enum class CpuType : uint8_t
{
Cpu,
Spc,
NecDsp,
CpuTypeCount
//SuperFx,
//Sa1,
};

View file

@ -5,6 +5,7 @@
#include "Cpu.h"
#include "Ppu.h"
#include "Spc.h"
#include "NecDsp.h"
#include "BaseCartridge.h"
#include "MemoryManager.h"
#include "EmuSettings.h"
@ -35,6 +36,7 @@ Debugger::Debugger(shared_ptr<Console> console)
_cpu = console->GetCpu();
_ppu = console->GetPpu();
_spc = console->GetSpc();
_cart = console->GetCartridge();
_settings = console->GetSettings();
_memoryManager = console->GetMemoryManager();
@ -42,8 +44,8 @@ Debugger::Debugger(shared_ptr<Console> console)
_watchExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(this, CpuType::Cpu));
_watchExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(this, CpuType::Spc));
_codeDataLogger.reset(new CodeDataLogger(console->GetCartridge()->DebugGetPrgRomSize(), _memoryManager.get()));
_memoryDumper.reset(new MemoryDumper(_ppu, console->GetSpc(), _memoryManager, console->GetCartridge()));
_codeDataLogger.reset(new CodeDataLogger(_cart->DebugGetPrgRomSize(), _memoryManager.get()));
_memoryDumper.reset(new MemoryDumper(_ppu, console->GetSpc(), _memoryManager, _cart));
_disassembler.reset(new Disassembler(console, _codeDataLogger, this));
_traceLogger.reset(new TraceLogger(this, _console));
_memoryAccessCounter.reset(new MemoryAccessCounter(this, _spc.get(), _memoryManager.get()));
@ -65,7 +67,7 @@ Debugger::Debugger(shared_ptr<Console> console)
_breakRequestCount = 0;
_suspendRequestCount = 0;
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
_codeDataLogger->LoadCdlFile(cdlFile);
RefreshCodeCache();
@ -78,7 +80,7 @@ Debugger::~Debugger()
void Debugger::Release()
{
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl");
_codeDataLogger->SaveCdlFile(cdlFile);
while(_executionStopped) {
@ -112,7 +114,7 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
}
DebugState debugState;
GetState(debugState);
GetState(debugState, true);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
_traceLogger->Log(debugState, disInfo);
@ -225,7 +227,7 @@ void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType
_disassembler->BuildCache(addressInfo, 0, CpuType::Spc);
DebugState debugState;
GetState(debugState);
GetState(debugState, true);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
_traceLogger->Log(debugState, disInfo);
@ -312,6 +314,21 @@ void Debugger::ProcessPpuCycle()
}
}
void Debugger::ProcessNecDspExec(uint32_t addr, uint32_t value)
{
if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) {
AddressInfo addressInfo { (int32_t)addr * 4, SnesMemoryType::DspProgramRom };
_disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp);
DebugState debugState;
GetState(debugState, true);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
_traceLogger->Log(debugState, disInfo);
}
}
void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId)
{
if(_suspendRequestCount) {
@ -391,7 +408,7 @@ int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalRes
{
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read };
DebugState state;
GetState(state);
GetState(state, false);
if(useCache) {
return _watchExpEval[(int)cpuType]->Evaluate(expression, state, resultType, operationInfo);
} else {
@ -532,12 +549,15 @@ void Debugger::SuspendDebugger(bool release)
}
}
void Debugger::GetState(DebugState &state)
void Debugger::GetState(DebugState &state, bool partialPpuState)
{
state.MasterClock = _memoryManager->GetMasterClock();
state.Cpu = _cpu->GetState();
state.Ppu = _ppu->GetState();
_ppu->GetState(state.Ppu, partialPpuState);
state.Spc = _spc->GetState();
if(_cart->GetDsp()) {
state.Dsp = _cart->GetDsp()->GetState();
}
}
AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress)
@ -585,7 +605,7 @@ void Debugger::SetCdlData(uint8_t *cdlData, uint32_t length)
void Debugger::RefreshCodeCache()
{
_disassembler->ResetPrgCache();
uint32_t prgRomSize = _console->GetCartridge()->DebugGetPrgRomSize();
uint32_t prgRomSize = _cart->DebugGetPrgRomSize();
AddressInfo addrInfo;
addrInfo.Type = SnesMemoryType::PrgRom;

View file

@ -36,7 +36,7 @@ private:
shared_ptr<Ppu> _ppu;
shared_ptr<Spc> _spc;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<BaseCartridge> _baseCartridge;
shared_ptr<BaseCartridge> _cart;
shared_ptr<EmuSettings> _settings;
@ -95,6 +95,8 @@ public:
void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
void ProcessPpuCycle();
void ProcessNecDspExec(uint32_t addr, uint32_t value);
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);
@ -107,7 +109,7 @@ public:
void BreakRequest(bool release);
void SuspendDebugger(bool release);
void GetState(DebugState &state);
void GetState(DebugState &state, bool partialPpuState);
AddressInfo GetAbsoluteAddress(AddressInfo relAddress);
AddressInfo GetRelativeAddress(AddressInfo absAddress);

View file

@ -4,6 +4,7 @@
#include "DisassemblyInfo.h"
#include "Cpu.h"
#include "Spc.h"
#include "NecDsp.h"
#include "Debugger.h"
#include "MemoryManager.h"
#include "LabelManager.h"
@ -39,11 +40,15 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
_spcRom = console->GetSpc()->GetSpcRom();
_spcRomSize = Spc::SpcRomSize;
_necDspProgramRom = console->GetCartridge()->GetDsp() ? console->GetCartridge()->GetDsp()->DebugGetProgramRom() : nullptr;
_necDspProgramRomSize = console->GetCartridge()->GetDsp() ? console->GetCartridge()->GetDsp()->DebugGetProgramRomSize() : 0;
_prgCache = vector<DisassemblyInfo>(_prgRomSize);
_sramCache = vector<DisassemblyInfo>(_sramSize);
_wramCache = vector<DisassemblyInfo>(_wramSize);
_spcRamCache = vector<DisassemblyInfo>(_spcRamSize);
_spcRomCache = vector<DisassemblyInfo>(_spcRomSize);
_necDspRomCache = vector<DisassemblyInfo>(_necDspProgramRomSize);
}
void Disassembler::GetSource(AddressInfo &info, uint8_t **source, uint32_t &size, vector<DisassemblyInfo> **cache)
@ -79,6 +84,12 @@ void Disassembler::GetSource(AddressInfo &info, uint8_t **source, uint32_t &size
size = _spcRomSize;
break;
case SnesMemoryType::DspProgramRom:
*source = _necDspProgramRom;
*cache = &_necDspRomCache;
size = _necDspProgramRomSize;
break;
default:
throw std::runtime_error("Disassembler::GetSource() invalid memory type");
}
@ -310,6 +321,7 @@ DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo &info)
case SnesMemoryType::SaveRam: disassemblyInfo = _sramCache[info.Address]; break;
case SnesMemoryType::SpcRam: disassemblyInfo = _spcRamCache[info.Address]; break;
case SnesMemoryType::SpcRom: disassemblyInfo = _spcRomCache[info.Address]; break;
case SnesMemoryType::DspProgramRom: disassemblyInfo = _necDspRomCache[info.Address]; break;
}
if(disassemblyInfo.IsInitialized()) {

View file

@ -30,6 +30,7 @@ private:
vector<DisassemblyInfo> _sramCache;
vector<DisassemblyInfo> _spcRamCache;
vector<DisassemblyInfo> _spcRomCache;
vector<DisassemblyInfo> _necDspRomCache;
SimpleLock _disassemblyLock;
vector<DisassemblyResult> _disassembly;
@ -47,6 +48,9 @@ private:
uint32_t _spcRamSize;
uint8_t *_spcRom;
uint32_t _spcRomSize;
uint8_t *_necDspProgramRom;
uint32_t _necDspProgramRomSize;
void GetSource(AddressInfo &info, uint8_t **source, uint32_t &size, vector<DisassemblyInfo> **cache);

View file

@ -5,6 +5,7 @@
#include "MemoryManager.h"
#include "CpuDisUtils.h"
#include "SpcDisUtils.h"
#include "NecDspDisUtils.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.h"
@ -47,6 +48,7 @@ void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr, LabelMana
switch(_cpuType) {
case CpuType::Cpu: CpuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break;
case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break;
case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break;
}
}
@ -55,6 +57,7 @@ int32_t DisassemblyInfo::GetEffectiveAddress(Console *console, void *cpuState)
switch(_cpuType) {
case CpuType::Cpu: return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState);
case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState);
case CpuType::NecDsp: return -1;
}
return -1;
}
@ -106,6 +109,7 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type)
switch(type) {
case CpuType::Cpu: return CpuDisUtils::GetOpSize(opCode, flags);
case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode);
case CpuType::NecDsp: return 4;
}
return 0;
}
@ -115,6 +119,7 @@ bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type)
switch(type) {
case CpuType::Cpu: return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL
case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK
case CpuType::NecDsp: return false;
}
return false;
}
@ -125,6 +130,7 @@ bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type)
switch(type) {
case CpuType::Cpu: return opCode == 0x60 || opCode == 0x6B || opCode == 0x40;
case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F;
case CpuType::NecDsp: return false;
}
return false;
@ -153,7 +159,8 @@ bool DisassemblyInfo::UpdateCpuFlags(uint8_t &cpuFlags)
return true;
default:
case CpuType::Spc: return false;
case CpuType::Spc:
case CpuType::NecDsp: return false;
}
}

View file

@ -670,7 +670,7 @@ int LuaApi::GetState(lua_State *lua)
LuaCallHelper l(lua);
checkparams();
DebugState state;
_debugger->GetState(state);
_debugger->GetState(state, true);
lua_newtable(lua);
lua_pushintvalue(masterClock, state.MasterClock);

View file

@ -3,6 +3,7 @@
#include "MemoryManager.h"
#include "Ppu.h"
#include "Spc.h"
#include "NecDsp.h"
#include "MemoryDumper.h"
#include "BaseCartridge.h"
#include "VideoDecoder.h"
@ -36,6 +37,10 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
case SnesMemoryType::CGRam: memcpy(_ppu->GetCgRam(), buffer, length); break;
case SnesMemoryType::SpcRam: memcpy(_spc->GetSpcRam(), buffer, length); break;
case SnesMemoryType::SpcRom: memcpy(_spc->GetSpcRom(), buffer, length); break;
case SnesMemoryType::DspProgramRom: memcpy(_cartridge->GetDsp()->DebugGetProgramRom(), buffer, length); break;
case SnesMemoryType::DspDataRom: memcpy(_cartridge->GetDsp()->DebugGetDataRom(), buffer, length); break;
case SnesMemoryType::DspDataRam: memcpy(_cartridge->GetDsp()->DebugGetDataRam(), buffer, length); break;
}
}
@ -54,6 +59,10 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
case SnesMemoryType::SpcRam: return Spc::SpcRamSize;
case SnesMemoryType::SpcRom: return Spc::SpcRomSize;
case SnesMemoryType::Register: return 0x10000;
case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRomSize() : 0;
case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRomSize() : 0;
case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0;
}
}
@ -82,6 +91,10 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
case SnesMemoryType::CGRam: memcpy(buffer, _ppu->GetCgRam(), Ppu::CgRamSize); break;
case SnesMemoryType::SpcRam: memcpy(buffer, _spc->GetSpcRam(), Spc::SpcRamSize); break;
case SnesMemoryType::SpcRom: memcpy(buffer, _spc->GetSpcRom(), Spc::SpcRomSize); break;
case SnesMemoryType::DspProgramRom: memcpy(buffer, _cartridge->GetDsp()->DebugGetProgramRom(), _cartridge->GetDsp()->DebugGetProgramRomSize()); break;
case SnesMemoryType::DspDataRom: memcpy(buffer, _cartridge->GetDsp()->DebugGetDataRom(), _cartridge->GetDsp()->DebugGetDataRomSize()); break;
case SnesMemoryType::DspDataRam: memcpy(buffer, _cartridge->GetDsp()->DebugGetDataRam(), _cartridge->GetDsp()->DebugGetDataRamSize()); break;
}
}
@ -114,6 +127,10 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
case SnesMemoryType::CGRam: _ppu->GetCgRam()[address] = value; break;
case SnesMemoryType::SpcRam: _spc->GetSpcRam()[address] = value; break;
case SnesMemoryType::SpcRom: _spc->GetSpcRom()[address] = value; break;
case SnesMemoryType::DspProgramRom: _cartridge->GetDsp()->DebugGetProgramRom()[address] = value;
case SnesMemoryType::DspDataRom: _cartridge->GetDsp()->DebugGetDataRom()[address] = value;
case SnesMemoryType::DspDataRam: _cartridge->GetDsp()->DebugGetDataRam()[address] = value;
}
}
@ -138,6 +155,10 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
case SnesMemoryType::CGRam: return _ppu->GetCgRam()[address];
case SnesMemoryType::SpcRam: return _spc->GetSpcRam()[address];
case SnesMemoryType::SpcRom: return _spc->GetSpcRom()[address];
case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp()->DebugGetProgramRom()[address];
case SnesMemoryType::DspDataRom: return _cartridge->GetDsp()->DebugGetDataRom()[address];
case SnesMemoryType::DspDataRam: return _cartridge->GetDsp()->DebugGetDataRam()[address];
}
}

519
Core/NecDsp.cpp Normal file
View file

@ -0,0 +1,519 @@
#include "stdafx.h"
#include "NecDsp.h"
#include "MemoryManager.h"
#include "Console.h"
#include "BaseCartridge.h"
#include "CartTypes.h"
#include "MessageManager.h"
#include "../Utilities/FolderUtilities.h"
NecDsp::NecDsp(Console* console, vector<uint8_t> &biosRom, uint16_t registerMask)
{
_console = console;
_memoryManager = console->GetMemoryManager().get();
_registerMask = registerMask;
for(int i = 0; i < 2048; i++) {
_progRom[i] = biosRom[i*3] | (biosRom[i*3 + 1] << 8) | (biosRom[i*3 + 2] << 16);
}
for(int i = 0; i < 1024; i++) {
_dataRom[i] = biosRom[2048*3 + i*2] | (biosRom[2048*3 + i*2 + 1] << 8);
}
}
bool NecDsp::LoadBios(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector<uint8_t> &biosData)
{
VirtualFile combinedBios(FolderUtilities::CombinePath(FolderUtilities::GetBiosFolder(), combinedFilename));
if(combinedBios.GetSize() == 0x2000) {
combinedBios.ReadFile(biosData);
return true;
} else {
VirtualFile splitBiosA(FolderUtilities::CombinePath(FolderUtilities::GetBiosFolder(), splitFilenameProgram));
VirtualFile splitBiosB(FolderUtilities::CombinePath(FolderUtilities::GetBiosFolder(), splitFilenameData));
if(splitBiosA.GetSize() == 0x1800 && splitBiosB.GetSize() == 0x800) {
splitBiosA.ReadFile(biosData);
vector<uint8_t> splitData;
splitBiosB.ReadFile(splitData);
biosData.insert(biosData.end(), splitData.begin(), splitData.end());
return true;
}
}
MessageManager::DisplayMessage("Error", "Could not find BIOS file for DSP: " + combinedFilename);
return false;
}
NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console *console)
{
bool biosLoaded = false;
vector<uint8_t> biosData;
switch(type) {
case CoprocessorType::DSP1: biosLoaded = LoadBios("dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", biosData); break;
case CoprocessorType::DSP1B: biosLoaded = LoadBios("dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", biosData); break;
case CoprocessorType::DSP2: biosLoaded = LoadBios("dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", biosData); break;
case CoprocessorType::DSP3: biosLoaded = LoadBios("dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", biosData); break;
case CoprocessorType::DSP4: biosLoaded = LoadBios("dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", biosData); break;
}
if(!biosLoaded) {
return nullptr;
}
NecDsp* dsp = nullptr;
MemoryManager* mm = console->GetMemoryManager().get();
if(console->GetCartridge()->GetCartFlags() & CartFlags::LoRom) {
dsp = new NecDsp(console, biosData, 0x4000);
for(int i = 0x30; i <= 0x3F; i++) {
mm->RegisterHandler((i << 16) | 0x8000, (i << 16) | 0xFFFF, dsp);
mm->RegisterHandler(((i + 0x80) << 16) | 0x8000, ((i + 0x80) << 16) | 0xFFFF, dsp);
}
} else if(console->GetCartridge()->GetCartFlags() & CartFlags::HiRom) {
dsp = new NecDsp(console, biosData, 0x1000);
for(int i = 0; i <= 0x1F; i++) {
mm->RegisterHandler((i << 16) | 0x6000, (i << 16) | 0x7FFF, dsp);
mm->RegisterHandler(((i + 0x80) << 16) | 0x6000, ((i + 0x80) << 16) | 0x7FFF, dsp);
}
}
return dsp;
}
void NecDsp::Reset()
{
_cycleCount = 0;
_state = {};
}
void NecDsp::Run()
{
uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * ((double)NecDsp::DspClockRate / _console->GetMasterClockRate()));
if(_inRqmLoop) {
_cycleCount = targetCycle;
_inRqmLoop = false;
return;
}
while(_cycleCount < targetCycle) {
_opCode = _progRom[_state.PC & 0x7FF];
_console->ProcessNecDspExec(_state.PC, _opCode);
_state.PC++;
switch(_opCode & 0xC00000) {
case 0x000000: ExecOp(); break;
case 0x400000: ExecAndReturn(); break;
case 0x800000: Jump(); break;
case 0xC00000: Load(_opCode & 0x0F, (uint16_t)(_opCode >> 6)); break;
}
//Store the multiplication's result
int32_t multResult = (int16_t)_state.K * (int16_t)_state.L;
_state.M = multResult >> 15;
_state.N = multResult << 1;
_cycleCount++;
}
}
uint8_t NecDsp::Read(uint32_t addr)
{
Run();
_inRqmLoop = false;
if(addr & _registerMask) {
return (_state.SR >> 8);
} else {
//DR
if(_state.SR & NecDspStatusFlags::DataRegControl) {
//8 bits
_state.SR &= ~NecDspStatusFlags::RequestForMaster;
return (uint8_t)_state.DR;
} else {
//16 bits
if(_state.SR & NecDspStatusFlags::DataRegStatus) {
_state.SR &= ~NecDspStatusFlags::RequestForMaster;
_state.SR &= ~NecDspStatusFlags::DataRegStatus;
return _state.DR >> 8;
} else {
_state.SR |= NecDspStatusFlags::DataRegStatus;
return (uint8_t)_state.DR;
}
}
}
}
void NecDsp::Write(uint32_t addr, uint8_t value)
{
Run();
_inRqmLoop = false;
if(addr & _registerMask) {
//SR
} else {
//DR
if(_state.SR & NecDspStatusFlags::DataRegControl) {
//8 bits
_state.SR &= ~NecDspStatusFlags::RequestForMaster;
_state.DR = (_state.DR & 0xFF00) | value;
} else {
//16 bits
if(_state.SR & NecDspStatusFlags::DataRegStatus) {
_state.SR &= ~NecDspStatusFlags::RequestForMaster;
_state.SR &= ~NecDspStatusFlags::DataRegStatus;
_state.DR = (_state.DR & 0xFF) | (value << 8);
} else {
_state.SR |= NecDspStatusFlags::DataRegStatus;
_state.DR = (_state.DR & 0xFF00) | value;
}
}
}
}
uint8_t NecDsp::Peek(uint32_t addr)
{
return 0;
}
void NecDsp::PeekBlock(uint8_t *output)
{
memset(output, 0, 0x1000);
}
AddressInfo NecDsp::GetAbsoluteAddress(uint32_t address)
{
return { -1, SnesMemoryType::CpuMemory };
}
void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source)
{
uint16_t result = 0;
//Select the accumulator/flags for the operation
uint8_t accSelect = (_opCode >> 15) & 0x01;
NecDspAccFlags flags = accSelect ? _state.FlagsB : _state.FlagsA;
uint16_t acc = accSelect ? _state.B : _state.A;
uint8_t otherCarry = accSelect ? _state.FlagsA.Carry : _state.FlagsB.Carry;
//Select the 2nd operand for the operation
uint8_t pSelect = (_opCode >> 20) & 0x03;
uint16_t p;
switch(pSelect) {
case 0: p = _ram[_state.DP & 0xFF]; break;
case 1: p = source; break;
case 2: p = _state.M; break;
case 3: p = _state.N; break;
}
//Perform the ALU operation, and set flags
switch(aluOperation) {
case 0x00: break;
case 0x01: result = acc | p; break;
case 0x02: result = acc & p; break;
case 0x03: result = acc ^ p; break;
case 0x04: result = acc - p; break;
case 0x05: result = acc + p; break;
case 0x06: result = acc - p - otherCarry; break;
case 0x07: result = acc + p + otherCarry; break;
case 0x08: result = acc - 1; p = 1; break;
case 0x09: result = acc + 1; p = 1; break;
case 0x0A: result = ~acc; break;
case 0x0B: result = (acc >> 1) | (acc & 0x8000); break;
case 0x0C: result = (acc << 1) | (uint8_t)otherCarry; break;
case 0x0D: result = (acc << 2) | 0x03; break;
case 0x0E: result = (acc << 4) | 0x0F; break;
case 0x0F: result = (acc << 8) | (acc >> 8); break;
}
flags.Zero = result == 0;
flags.Sign0 = (result & 0x8000) >> 15;
if(!flags.Overflow1) {
flags.Sign1 = flags.Sign0;
}
switch(aluOperation) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x0A: case 0x0D: case 0x0E: case 0x0F:
flags.Carry = false;
flags.Overflow0 = false;
flags.Overflow1 = false;
break;
case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: {
uint16_t overflow = (acc ^ result) & (p ^ ((aluOperation & 0x01) ? result : acc));
flags.Overflow0 = (bool)((overflow & 0x8000) >> 15);
if(flags.Overflow0 && flags.Overflow1) {
flags.Overflow1 = flags.Sign0 == flags.Sign1;
} else {
flags.Overflow1 |= flags.Overflow0;
}
flags.Carry = (bool)(((acc ^ p ^ result ^ overflow) & 0x8000) >> 15);
break;
}
case 0x0B:
flags.Carry = (bool)(acc & 0x01);
flags.Overflow0 = false;
flags.Overflow1 = false;
break;
case 0x0C:
flags.Carry = (bool)((acc >> 15) & 0x01);
flags.Overflow0 = false;
flags.Overflow1 = false;
break;
}
//Update selected accumulator/flags with the operation's results
if(accSelect) {
_state.B = result;
_state.FlagsB = flags;
} else {
_state.A = result;
_state.FlagsA = flags;
}
}
void NecDsp::UpdateDataPointer()
{
uint16_t dp = _state.DP;
switch((_opCode >> 13) & 0x03) {
case 0: break; //NOP
case 1: dp = (dp & 0xF0) | ((dp + 1) & 0x0F); break; //Increment lower nibble, with no carry
case 2: dp = (dp & 0xF0) | ((dp - 1) & 0x0F); break; //Decrement lower nibble, with no carry
case 3: dp &= 0xF0; break; //Clear lower nibble
}
uint8_t dpHighModify = (_opCode >> 9) & 0x0F;
_state.DP = dp ^ (dpHighModify << 4);
}
void NecDsp::ExecOp()
{
uint8_t aluOperation = (_opCode >> 16) & 0x0F;
uint16_t source = GetSourceValue((_opCode >> 4) & 0x0F);
//First, process the ALU operation, if needed
if(aluOperation) {
RunApuOp(aluOperation, source);
}
//Then transfer data from source to destination
uint8_t dest = _opCode & 0x0F;
Load(dest, source);
if(dest != 0x04) {
//Destination was not the data pointer (DP), update it
UpdateDataPointer();
}
uint8_t rpDecrement = (_opCode >> 8) & 0x01;
if(rpDecrement && dest != 0x05) {
//Destination was not the rom pointer (RP), decrement it
_state.RP--;
}
}
void NecDsp::ExecAndReturn()
{
ExecOp();
_state.SP = (_state.SP - 1) & 0x03;
_state.PC = _stack[_state.SP];
}
void NecDsp::Jump()
{
uint8_t bank = _opCode & 0x03;
uint16_t address = (_opCode >> 2) & 0x7FF;
uint16_t target = (_state.PC & 0x2000) | (bank << 11) | address;
uint32_t jmpCond = 0;
uint16_t jmpType = (_opCode >> 13) & 0x1FF;
switch(jmpType) {
case 0x00: _state.PC = _state.SerialOut; break;
case 0x80: jmpCond = !_state.FlagsA.Carry; break;
case 0x82: jmpCond = _state.FlagsA.Carry; break;
case 0x84: jmpCond = !_state.FlagsB.Carry; break;
case 0x86: jmpCond = _state.FlagsB.Carry; break;
case 0x88: jmpCond = !_state.FlagsA.Zero; break;
case 0x8A: jmpCond = _state.FlagsA.Zero; break;
case 0x8C: jmpCond = !_state.FlagsB.Zero; break;
case 0x8E: jmpCond = _state.FlagsB.Zero; break;
case 0x90: jmpCond = !_state.FlagsA.Overflow0; break;
case 0x92: jmpCond = _state.FlagsA.Overflow0; break;
case 0x94: jmpCond = !_state.FlagsB.Overflow0; break;
case 0x96: jmpCond = _state.FlagsB.Overflow0; break;
case 0x98: jmpCond = !_state.FlagsA.Overflow1; break;
case 0x9A: jmpCond = _state.FlagsA.Overflow1; break;
case 0x9C: jmpCond = !_state.FlagsB.Overflow1; break;
case 0x9E: jmpCond = _state.FlagsB.Overflow1; break;
case 0xA0: jmpCond = !_state.FlagsA.Sign0; break;
case 0xA2: jmpCond = _state.FlagsA.Sign0; break;
case 0xA4: jmpCond = !_state.FlagsB.Sign0; break;
case 0xA6: jmpCond = _state.FlagsB.Sign0; break;
case 0xA8: jmpCond = !_state.FlagsA.Sign1; break;
case 0xAA: jmpCond = _state.FlagsA.Sign1; break;
case 0xAC: jmpCond = !_state.FlagsB.Sign1; break;
case 0xAE: jmpCond = _state.FlagsB.Sign1; break;
case 0xB0: jmpCond = !(_state.DP & 0x0F); break;
case 0xB1: jmpCond = _state.DP & 0x0F; break;
case 0xB2: jmpCond = (_state.DP & 0x0F) == 0x0F; break;
case 0xB3: jmpCond = (_state.DP & 0x0F) != 0x0F; break;
case 0xB4: jmpCond = !(_state.SR & NecDspStatusFlags::SerialInControl); break;
case 0xB6: jmpCond = _state.SR & NecDspStatusFlags::SerialInControl; break;
case 0xB8: jmpCond = !(_state.SR & NecDspStatusFlags::SerialOutControl); break;
case 0xBA: jmpCond = _state.SR & NecDspStatusFlags::SerialOutControl; break;
case 0xBC: jmpCond = !(_state.SR & NecDspStatusFlags::RequestForMaster); break;
case 0xBE: jmpCond = _state.SR & NecDspStatusFlags::RequestForMaster; break;
case 0x100: _state.PC = target & ~0x2000; break;
case 0x101: _state.PC = target | 0x2000; break;
case 0x140:
_stack[_state.SP] = _state.PC;
_state.SP = (_state.SP + 1) & 0x03;
_state.PC = target & ~0x2000;
break;
case 0x141:
_stack[_state.SP] = _state.PC;
_state.SP = (_state.SP + 1) & 0x03;
_state.PC = target | 0x2000;
break;
}
if(jmpCond) {
if((_state.PC - 1 == target) && (jmpType == 0xBC || jmpType == 0xBE)) {
//CPU is in a wait loop for RQM, skip emulation until the CPU reads/writes from the IO registers
_inRqmLoop = true;
}
_state.PC = target;
}
}
void NecDsp::Load(uint8_t dest, uint16_t value)
{
switch(dest) {
case 0x00: break;
case 0x01: _state.A = value; break;
case 0x02: _state.B = value; break;
case 0x03: _state.TR = value; break;
case 0x04: _state.DP = value; break;
case 0x05: _state.RP = value; break;
case 0x06:
_state.DR = value;
_state.SR |= NecDspStatusFlags::RequestForMaster;
break;
case 0x07:
_state.SR = (_state.SR & 0x907C) | (value & ~0x907C);
break;
case 0x08: _state.SerialOut = value; break;
case 0x09: _state.SerialOut = value; break;
case 0x0A: _state.K = value; break;
case 0x0B:
_state.K = value;
_state.L = _dataRom[_state.RP & 0x3FF];
break;
case 0x0C:
_state.L = value;
_state.K = _ram[(_state.DP | 0x40) & 0xFF];
break;
case 0x0D: _state.L = value; break;
case 0x0E: _state.TRB = value; break;
case 0x0F: _ram[_state.DP & 0xFF] = value; break;
default:
throw std::runtime_error("DSP-1: invalid destination");
}
}
uint16_t NecDsp::GetSourceValue(uint8_t source)
{
switch(source) {
case 0x00: return _state.TRB;
case 0x01: return _state.A;
case 0x02: return _state.B;
case 0x03: return _state.TR;
case 0x04: return _state.DP;
case 0x05: return _state.RP;
case 0x06: return _dataRom[_state.RP & 0x3FF];
case 0x07: return 0x8000 - _state.FlagsA.Sign1;
case 0x08:
_state.SR |= NecDspStatusFlags::RequestForMaster;
return _state.DR;
case 0x09: return _state.DR;
case 0x0A: return _state.SR;
case 0x0B: return _state.SerialIn;
case 0x0C: return _state.SerialIn;
case 0x0D: return _state.K;
case 0x0E: return _state.L;
case 0x0F: return _ram[_state.DP & 0xFF];
}
throw std::runtime_error("DSP-1: invalid source");
}
uint8_t* NecDsp::DebugGetProgramRom()
{
return (uint8_t*)_progRom;
}
uint8_t* NecDsp::DebugGetDataRom()
{
return (uint8_t*)_dataRom;
}
uint8_t* NecDsp::DebugGetDataRam()
{
return (uint8_t*)_ram;
}
uint32_t NecDsp::DebugGetProgramRomSize()
{
return 2048 * 4;
}
uint32_t NecDsp::DebugGetDataRomSize()
{
return 1024 * 2;
}
uint32_t NecDsp::DebugGetDataRamSize()
{
return 256 * 2;
}
NecDspState NecDsp::GetState()
{
return _state;
}
void NecDsp::Serialize(Serializer &s)
{
s.Stream(
_state.A, _state.B, _state.DP, _state.DR, _state.K, _state.L, _state.M, _state.N, _state.PC,
_state.RP, _state.SerialIn, _state.SerialOut, _state.SP, _state.SR, _state.TR, _state.TRB,
_state.FlagsA.Carry, _state.FlagsA.Overflow0, _state.FlagsA.Overflow1, _state.FlagsA.Sign0, _state.FlagsA.Sign1, _state.FlagsA.Zero,
_state.FlagsB.Carry, _state.FlagsB.Overflow0, _state.FlagsB.Overflow1, _state.FlagsB.Sign0, _state.FlagsB.Sign1, _state.FlagsB.Zero
);
s.Stream(_opCode, _cycleCount, _inRqmLoop);
s.StreamArray<uint16_t>(_ram, 256);
s.StreamArray<uint16_t>(_stack, 4);
}

64
Core/NecDsp.h Normal file
View file

@ -0,0 +1,64 @@
#pragma once
#include "stdafx.h"
#include "NecDspTypes.h"
#include "BaseCoprocessor.h"
class Console;
class MemoryManager;
enum class CoprocessorType;
class NecDsp final : public BaseCoprocessor
{
private:
static constexpr int DspClockRate = 7600000;
Console* _console = nullptr;
MemoryManager* _memoryManager = nullptr;
NecDspState _state = {};
uint32_t _opCode = 0;
uint32_t _progRom[2048] = {};
uint16_t _dataRom[1024] = {};
uint16_t _ram[256] = {};
uint16_t _stack[4] = {};
uint64_t _cycleCount = 0;
uint16_t _registerMask = 0;
bool _inRqmLoop = false;
void RunApuOp(uint8_t aluOperation, uint16_t source);
void UpdateDataPointer();
void ExecOp();
void ExecAndReturn();
void Jump();
void Load(uint8_t dest, uint16_t value);
uint16_t GetSourceValue(uint8_t source);
NecDsp(Console* console, vector<uint8_t> &biosRom, uint16_t registerMask);
static bool LoadBios(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector<uint8_t> &biosData);
public:
static NecDsp* InitCoprocessor(CoprocessorType type, Console* console);
void Reset();
void Run();
uint8_t Read(uint32_t addr) override;
void Write(uint32_t addr, uint8_t value) override;
uint8_t Peek(uint32_t addr) override;
void PeekBlock(uint8_t * output) override;
AddressInfo GetAbsoluteAddress(uint32_t address) override;
uint8_t* DebugGetProgramRom();
uint8_t* DebugGetDataRom();
uint8_t* DebugGetDataRam();
uint32_t DebugGetProgramRomSize();
uint32_t DebugGetDataRomSize();
uint32_t DebugGetDataRamSize();
NecDspState GetState();
void Serialize(Serializer &s) override;
};

131
Core/NecDspDisUtils.cpp Normal file
View file

@ -0,0 +1,131 @@
#include "stdafx.h"
#include "NecDspDisUtils.h"
#include "DisassemblyInfo.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FastString.h"
void NecDspDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager)
{
constexpr const char* aluOperations[16] = { "NOP ", "OR ", "AND ", "XOR ", "SUB ", "ADD ", "SBC ", "ADC ", "DEC" , "INC ", "CMP ", "SHR1 ", "SHL1 ", "SHL2 ", "SHL4 ", "XCHG " };
constexpr const char* sourceNames[16] = { "TRB", "A", "B", "TR", "DP", "RP", "ROM", "SGN", "DR", "DRNF", "SR", "SIM", "SIL" ,"K", "L", "MEM" };
constexpr const char* destNames[16] = { "NON", "A", "B", "TR", "DP", "RP", "DR", "SR", "SOL", "SOM", "K", "KLR", "KLM", "L", "TRB", "MEM" };
constexpr const char* dataPointerOp[4] = { "DPL:NOP", "DPL:INC", "DPL:DEC", "DPL:CLR" };
FastString str;
uint32_t opCode = *(uint32_t*)info.GetByteCode();
uint8_t operationType = (opCode >> 22) & 0x03;
if(operationType <= 1) {
//OP or RT
uint8_t aluOperation = (opCode >> 16) & 0x0F;
uint8_t source = (opCode >> 4) & 0x0F;
uint8_t accSelect = (opCode >> 15) & 0x01;
if(aluOperation) {
str.Write(aluOperations[aluOperation], " ");
if(aluOperation <= 7) {
uint8_t pSelect = (opCode >> 20) & 0x03;
switch(pSelect) {
case 0: str.Write("RAM, "); break;
case 1: str.Write(sourceNames[source], ", "); break;
case 2: str.Write("M, "); break;
case 3: str.Write("N, "); break;
}
}
str.Write(accSelect ? "B" : "A");
}
uint8_t dest = opCode & 0x0F;
if(dest) {
str.Delimiter(" | ");
str.Write("MOV ");
str.Write(sourceNames[source], ", ");
str.Write(destNames[dest]);
}
uint8_t dpLow = (opCode >> 13) & 0x03;
if(dpLow) {
str.Delimiter(" | ");
str.Write(dataPointerOp[dpLow]);
}
uint8_t dpHighModify = (opCode >> 9) & 0x0F;
if(dpHighModify) {
str.Delimiter(" | ");
str.Write("DPH:$", HexUtilities::ToHex(dpHighModify));
}
uint8_t rpDecrement = (opCode >> 8) & 0x01;
if(rpDecrement) {
str.Delimiter(" | ");
str.Write("RP:DEC");
}
if(operationType == 1) {
str.Delimiter(" | ");
str.Write("RET");
}
} else if(operationType == 2) {
//Jump
uint8_t bank = opCode & 0x03; //should be 8 bits?
uint16_t address = (opCode >> 2) & 0x7FF;
uint16_t target = (memoryAddr & 0x2000) | (bank << 11) | address;
switch((opCode >> 13) & 0x1FF) {
case 0x00: str.Write("JMPSO"); target = 0; break;
case 0x80: str.Write("JNCA"); break;
case 0x82: str.Write("JCA"); break;
case 0x84: str.Write("JNCB"); break;
case 0x86: str.Write("JCB"); break;
case 0x88: str.Write("JNZA"); break;
case 0x8A: str.Write("JZA"); break;
case 0x8C: str.Write("JNZB"); break;
case 0x8E: str.Write("JZB"); break;
case 0x90: str.Write("JNOVA0"); break;
case 0x92: str.Write("JOVA0"); break;
case 0x94: str.Write("JNOVB0"); break;
case 0x96: str.Write("JOVB0"); break;
case 0x98: str.Write("JNOVA1"); break;
case 0x9A: str.Write("JOVA1"); break;
case 0x9C: str.Write("JNOVB1"); break;
case 0x9E: str.Write("JOVB1"); break;
case 0xA0: str.Write("JNSA0"); break;
case 0xA2: str.Write("JSA0"); break;
case 0xA4: str.Write("JNSB0"); break;
case 0xA6: str.Write("JSB0"); break;
case 0xA8: str.Write("JNSA1"); break;
case 0xAA: str.Write("JSA1"); break;
case 0xAC: str.Write("JNSB1"); break;
case 0xAE: str.Write("JSB1"); break;
case 0xB0: str.Write("JDPL0"); break;
case 0xB1: str.Write("JDPLN0"); break;
case 0xB2: str.Write("JDPLF"); break;
case 0xB3: str.Write("JDPLNF"); break;
case 0xB4: str.Write("JNSIAK"); break;
case 0xB6: str.Write("JSIAK"); break;
case 0xB8: str.Write("JNSOAK"); break;
case 0xBA: str.Write("JSOAK"); break;
case 0xBC: str.Write("JNRQM"); break;
case 0xBE: str.Write("JRQM"); break;
case 0x100: str.Write("LJMP"); target &= ~0x2000; break;
case 0x101: str.Write("HJMP"); target |= 0x2000; break;
case 0x140: str.Write("LCALL"); target &= ~0x2000; break;
case 0x141: str.Write("HCALL"); target |= 0x2000; break;
default: str.Write("<unknown jump>"); break;
}
str.Write(" $", HexUtilities::ToHex(target));
} else if(operationType == 3) {
//Load
uint16_t value = opCode >> 6;
uint8_t dest = opCode & 0x0F;
str.Write("LD ");
str.Write("$", HexUtilities::ToHex(value), ", ");
str.Write(destNames[dest]);
}
out += str.ToString();
}

13
Core/NecDspDisUtils.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "stdafx.h"
class DisassemblyInfo;
class Console;
class LabelManager;
struct NecDspState;
class NecDspDisUtils
{
public:
static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager);
};

77
Core/NecDspTypes.h Normal file
View file

@ -0,0 +1,77 @@
#pragma once
#include "stdafx.h"
struct NecDspAccFlags
{
bool Carry;
bool Zero;
bool Overflow0;
bool Overflow1;
bool Sign0;
bool Sign1;
};
namespace NecDspStatusFlags
{
enum NecDspStatusFlags
{
RequestForMaster = 0x8000,
UserFlag1 = 0x4000,
UserFlag0 = 0x2000,
DataRegStatus = 0x1000,
Dma = 0x0800,
DataRegControl = 0x0400,
SerialOutControl = 0x0200,
SerialInControl = 0x0100,
EnableInterrupt = 0x0080,
};
}
struct NecDspState
{
/* Accumulator A */
uint16_t A;
NecDspAccFlags FlagsA;
/* Accumulator B */
uint16_t B;
NecDspAccFlags FlagsB;
/* Temporary Register */
uint16_t TR;
/* Temporary Register B */
uint16_t TRB;
/* Program counter */
uint16_t PC;
/* ROM pointer */
uint16_t RP;
/* Data pointer */
uint16_t DP;
/* Data Register */
uint16_t DR;
/* Status Register */
uint16_t SR;
/* Multiplication registers */
uint16_t K;
uint16_t L;
/* Multiplication output registers */
uint16_t M;
uint16_t N;
/* Serial output - not emulated */
uint16_t SerialOut;
/* Serial input- not emulated */
uint16_t SerialIn;
/* Stack pointer */
uint8_t SP;
};

View file

@ -108,26 +108,32 @@ uint16_t Ppu::GetVblankStart()
PpuState Ppu::GetState()
{
PpuState state;
GetState(state, false);
return state;
}
void Ppu::GetState(PpuState &state, bool returnPartialState)
{
state.Cycle = GetCycle();
state.Scanline = _scanline;
state.HClock = _memoryManager->GetHClock();
state.FrameCount = _frameCount;
state.OverscanMode = _overscanMode;
state.BgMode = _bgMode;
state.DirectColorMode = _directColorMode;
state.Mode7 = _mode7;
state.Layers[0] = _layerConfig[0];
state.Layers[1] = _layerConfig[1];
state.Layers[2] = _layerConfig[2];
state.Layers[3] = _layerConfig[3];
if(!returnPartialState) {
state.OverscanMode = _overscanMode;
state.BgMode = _bgMode;
state.DirectColorMode = _directColorMode;
state.Mode7 = _mode7;
state.Layers[0] = _layerConfig[0];
state.Layers[1] = _layerConfig[1];
state.Layers[2] = _layerConfig[2];
state.Layers[3] = _layerConfig[3];
state.OamMode = _oamMode;
state.OamBaseAddress = _oamBaseAddress;
state.OamAddressOffset = _oamAddressOffset;
state.EnableOamPriority = _enableOamPriority;
state.ObjInterlace = _objInterlace;
return state;
state.OamMode = _oamMode;
state.OamBaseAddress = _oamBaseAddress;
state.OamAddressOffset = _oamAddressOffset;
state.EnableOamPriority = _enableOamPriority;
state.ObjInterlace = _objInterlace;
}
}
template<bool hiResMode>

View file

@ -252,6 +252,7 @@ public:
uint16_t GetVblankStart();
PpuState GetState();
void GetState(PpuState &state, bool returnPartialState);
bool ProcessEndOfScanline(uint16_t hClock);
uint16_t GetLastScanline();

View file

@ -7,6 +7,9 @@
#include "Debugger.h"
#include "MemoryManager.h"
#include "LabelManager.h"
#include "CpuTypes.h"
#include "SpcTypes.h"
#include "NecDspTypes.h"
#include "../Utilities/HexUtilities.h"
string TraceLogger::_executionTrace = "";
@ -51,6 +54,7 @@ void TraceLogger::SetOptions(TraceLoggerOptions options)
_logCpu[(int)CpuType::Cpu] = options.LogCpu;
_logCpu[(int)CpuType::Spc] = options.LogSpc;
_logCpu[(int)CpuType::NecDsp] = options.LogNecDsp;
string condition = _options.Condition;
string format = _options.Format;
@ -67,6 +71,7 @@ void TraceLogger::SetOptions(TraceLoggerOptions options)
ParseFormatString(_rowParts, format);
ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,15h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]");
ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,15h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]");
}
void TraceLogger::ParseFormatString(vector<RowPart> &rowParts, string format)
@ -330,6 +335,46 @@ void TraceLogger::GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuS
output += _options.UseWindowsEol ? "\r\n" : "\n";
}
void TraceLogger::GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
{
int originalSize = (int)output.size();
uint32_t pcAddress = cpuState.PC;
for(RowPart& rowPart : _dspRowParts) {
switch(rowPart.DataType) {
case RowDataType::Text: output += rowPart.Text; break;
case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break;
case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break;
case RowDataType::A:
output += "A:" + HexUtilities::ToHex(cpuState.A);
output += " B:" + HexUtilities::ToHex(cpuState.B);
output += " DR:" + HexUtilities::ToHex(cpuState.DR);
output += " DP:" + HexUtilities::ToHex(cpuState.DP);
output += " SR:" + HexUtilities::ToHex(cpuState.SR);
output += " K:" + HexUtilities::ToHex(cpuState.K);
output += " L:" + HexUtilities::ToHex(cpuState.L);
output += " M:" + HexUtilities::ToHex(cpuState.M);
output += " N:" + HexUtilities::ToHex(cpuState.N);
output += " RP:" + HexUtilities::ToHex(cpuState.RP);
output += " TR:" + HexUtilities::ToHex(cpuState.TR);
output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " ";
//output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA);
//output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB);
WriteValue(output, cpuState.A, rowPart);
break;
case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
default: break;
}
}
output += _options.UseWindowsEol ? "\r\n" : "\n";
}
/*
bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo)
{
@ -354,6 +399,7 @@ void TraceLogger::GetTraceRow(string &output, DisassemblyInfo &disassemblyInfo,
switch(disassemblyInfo.GetCpuType()) {
case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo); break;
case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); break;
case CpuType::NecDsp: GetTraceRow(output, state.Dsp, state.Ppu, disassemblyInfo); break;
}
}
@ -390,10 +436,13 @@ void TraceLogger::LogNonExec(OperationInfo& operationInfo)
void TraceLogger::Log(DebugState &state, DisassemblyInfo &disassemblyInfo)
{
auto lock = _lock.AcquireSafe();
//if(ConditionMatches(state, disassemblyInfo, operationInfo)) {
AddRow(disassemblyInfo, state);
//}
if(_logCpu[(int)disassemblyInfo.GetCpuType()]) {
//For the sake of performance, only log data for the CPUs we're actively displaying/logging
auto lock = _lock.AcquireSafe();
//if(ConditionMatches(state, disassemblyInfo, operationInfo)) {
AddRow(disassemblyInfo, state);
//}
}
}
void TraceLogger::Clear()
@ -415,7 +464,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
}
bool enabled = false;
for(int i = 0; i <= (int)CpuType::Spc; i++) {
for(int i = 0; i < (int)CpuType::CpuTypeCount; i++) {
enabled |= _logCpu[i];
}
@ -440,6 +489,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
switch(cpuType) {
case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((_stateCacheCopy[index].Cpu.K << 16) | _stateCacheCopy[index].Cpu.PC) + "\x1"; break;
case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(_stateCacheCopy[index].Spc.PC) + "\x1"; break;
case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(_stateCacheCopy[index].Dsp.PC) + "\x1"; break;
}
string byteCode;

View file

@ -16,6 +16,7 @@ struct TraceLoggerOptions
{
bool LogCpu;
bool LogSpc;
bool LogNecDsp;
bool ShowExtraInfo;
bool IndentCode;
@ -75,8 +76,9 @@ private:
vector<RowPart> _rowParts;
vector<RowPart> _spcRowParts;
vector<RowPart> _dspRowParts;
bool _logCpu[(int)CpuType::Spc + 1] = {};
bool _logCpu[(int)CpuType::CpuTypeCount] = {};
bool _pendingLog;
//CpuState _lastState;
@ -108,6 +110,7 @@ private:
void GetTraceRow(string &output, DisassemblyInfo &disassemblyInfo, DebugState &state);
void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
void GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
void GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
template<typename T> void WriteValue(string &output, T value, RowPart& rowPart);
@ -115,6 +118,8 @@ public:
TraceLogger(Debugger* debugger, shared_ptr<Console> console);
~TraceLogger();
__forceinline bool IsCpuLogged(CpuType type) { return _logCpu[(int)type]; }
void Log(DebugState &state, DisassemblyInfo &disassemblyInfo);
void Clear();
//void LogNonExec(OperationInfo& operationInfo);

View file

@ -60,7 +60,7 @@ extern "C"
DllExport int32_t __stdcall EvaluateExpression(char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, cpuType, *resultType, useCache); }
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize); }
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state); }
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state, false); }
DllExport void __stdcall SetMemoryState(SnesMemoryType type, uint8_t *buffer, int32_t length) { GetDebugger()->GetMemoryDumper()->SetMemoryState(type, buffer, length); }
DllExport uint32_t __stdcall GetMemorySize(SnesMemoryType type) { return GetDebugger()->GetMemoryDumper()->GetMemorySize(type); }

View file

@ -47,6 +47,7 @@ namespace Mesen.GUI.Config
{
public bool LogCpu;
public bool LogSpc;
public bool LogNecDsp;
public bool ShowByteCode;
public bool ShowRegisters;

View file

@ -163,6 +163,13 @@ namespace Mesen.GUI.Debugger
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam));
if(DebugApi.GetMemorySize(SnesMemoryType.DspProgramRom) > 0) {
cboMemoryType.Items.Add("-");
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.DspProgramRom));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.DspDataRom));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.DspDataRam));
}
cboMemoryType.SelectedIndex = 0;
cboMemoryType.SetEnumValue(originalValue);
cboMemoryType.SelectedIndexChanged += this.cboMemoryType_SelectedIndexChanged;

View file

@ -90,6 +90,7 @@ namespace Mesen.GUI.Debugger
this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.chkLogNecDsp = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel1.SuspendLayout();
this.grpLogOptions.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
@ -202,6 +203,7 @@ namespace Mesen.GUI.Debugger
this.tableLayoutPanel2.Controls.Add(this.chkLogCpu, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.chkLogSpc, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.lblTarget, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.chkLogNecDsp, 3, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
@ -809,6 +811,18 @@ namespace Mesen.GUI.Debugger
this.mnuRefresh.Text = "Refresh";
this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click);
//
// chkLogNecDsp
//
this.chkLogNecDsp.AutoSize = true;
this.chkLogNecDsp.Checked = true;
this.chkLogNecDsp.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkLogNecDsp.Location = new System.Drawing.Point(301, 3);
this.chkLogNecDsp.Name = "chkLogNecDsp";
this.chkLogNecDsp.Size = new System.Drawing.Size(57, 17);
this.chkLogNecDsp.TabIndex = 24;
this.chkLogNecDsp.Text = "DSP-n";
this.chkLogNecDsp.UseVisualStyleBackColor = true;
//
// frmTraceLogger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -905,5 +919,6 @@ namespace Mesen.GUI.Debugger
private System.Windows.Forms.CheckBox chkLogSpc;
private System.Windows.Forms.Label lblTarget;
private System.Windows.Forms.Button btnClearLog;
private System.Windows.Forms.CheckBox chkLogNecDsp;
}
}

View file

@ -47,6 +47,7 @@ namespace Mesen.GUI.Debugger
_entityBinder.AddBinding(nameof(TraceLoggerOptions.LogCpu), chkLogCpu);
_entityBinder.AddBinding(nameof(TraceLoggerOptions.LogSpc), chkLogSpc);
_entityBinder.AddBinding(nameof(TraceLoggerOptions.LogNecDsp), chkLogNecDsp);
_entityBinder.AddBinding(nameof(TraceLoggerOptions.ShowByteCode), chkShowByteCode);
//_entityBinder.AddBinding(nameof(TraceLoggerOptions.ShowCpuCycles), chkShowCpuCycles);
@ -141,6 +142,9 @@ namespace Mesen.GUI.Debugger
_entityBinder.UpdateObject();
//Disable logging when we close the trace logger
SetOptions(true);
ConfigManager.ApplyChanges();
if(_loggingEnabled) {
@ -206,14 +210,15 @@ namespace Mesen.GUI.Debugger
}
}
private void SetOptions()
private void SetOptions(bool disableLogging = false)
{
_entityBinder.UpdateObject();
TraceLoggerOptions options = (TraceLoggerOptions)_entityBinder.Entity;
InteropTraceLoggerOptions interopOptions = new InteropTraceLoggerOptions();
interopOptions.LogCpu = options.LogCpu;
interopOptions.LogSpc = options.LogSpc;
interopOptions.LogCpu = !disableLogging && options.LogCpu;
interopOptions.LogSpc = !disableLogging && options.LogSpc;
interopOptions.LogNecDsp = !disableLogging && options.LogNecDsp;
interopOptions.IndentCode = options.IndentCode;
interopOptions.ShowExtraInfo = options.ShowExtraInfo;
interopOptions.UseLabels = options.UseLabels;
@ -542,8 +547,11 @@ namespace Mesen.GUI.Debugger
public class TraceLoggerStyleProvider : ctrlTextbox.ILineStyleProvider
{
private Color _spcColor = Color.FromArgb(030, 145, 030);
private Color _spcColor = Color.FromArgb(30, 145, 30);
private Color _spcBgColor = Color.FromArgb(230, 245, 230);
private Color _dspColor = Color.FromArgb(30, 30, 145);
private Color _dspBgColor = Color.FromArgb(230, 230, 245);
private List<int> _flags;
public TraceLoggerStyleProvider(List<int> lineFlags)
@ -559,10 +567,17 @@ namespace Mesen.GUI.Debugger
public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
{
int count = _flags.Count - 1;
return new LineProperties() {
AddressColor = _flags[count - lineIndex] == 3 ? (Color?)_spcColor : null,
LineBgColor = _flags[count - lineIndex] == 3 ? (Color?)_spcBgColor : null
};
int cpuType = _flags[count - lineIndex];
if(cpuType == 3) {
//SPC
return new LineProperties() { AddressColor = _spcColor, LineBgColor = _spcBgColor };
} else if(cpuType == 4) {
//DSP
return new LineProperties() { AddressColor = _dspColor, LineBgColor = _dspBgColor };
} else {
//CPU
return new LineProperties() { AddressColor = null, LineBgColor = null };
}
}
}
}

View file

@ -951,6 +951,9 @@
<Value ID="CGRam">CG RAM (Palette)</Value>
<Value ID="SpcRam">SPC RAM</Value>
<Value ID="SpcRom">SPC ROM (IPL)</Value>
<Value ID="DspProgramRom">DSP-n - Program ROM</Value>
<Value ID="DspDataRom">DSP-n - Data ROM</Value>
<Value ID="DspDataRam">DSP-n - Data RAM</Value>
<Value ID="Register">Register</Value>
</Enum>
<Enum ID="TileFormat">

View file

@ -169,7 +169,10 @@ namespace Mesen.GUI
CGRam,
SpcRam,
SpcRom,
Register
DspProgramRom,
DspDataRom,
DspDataRam,
Register,
}
public static class SnesMemoryTypeExtensions
@ -381,12 +384,45 @@ namespace Mesen.GUI
public SpcTimer Timer2;
};
public struct NecDspAccFlags
{
[MarshalAs(UnmanagedType.I1)] public bool Carry;
[MarshalAs(UnmanagedType.I1)] public bool Zero;
[MarshalAs(UnmanagedType.I1)] public bool Overflow0;
[MarshalAs(UnmanagedType.I1)] public bool Overflow1;
[MarshalAs(UnmanagedType.I1)] public bool Sign0;
[MarshalAs(UnmanagedType.I1)] public bool Sign1;
}
public struct NecDspState
{
public UInt16 A;
public NecDspAccFlags FlagsA;
public UInt16 B;
public NecDspAccFlags FlagsB;
public UInt16 TR;
public UInt16 TRB;
public UInt16 PC;
public UInt16 RP;
public UInt16 DP;
public UInt16 DR;
public UInt16 SR;
public UInt16 K;
public UInt16 L;
public UInt16 M;
public UInt16 N;
public UInt16 SerialOut;
public UInt16 SerialIn;
public byte SP;
}
public struct DebugState
{
public UInt64 MasterClock;
public CpuState Cpu;
public PpuState Ppu;
public SpcState Spc;
public NecDspState NecDsp;
}
public enum MemoryOperationType
@ -530,6 +566,7 @@ namespace Mesen.GUI
{
[MarshalAs(UnmanagedType.I1)] public bool LogCpu;
[MarshalAs(UnmanagedType.I1)] public bool LogSpc;
[MarshalAs(UnmanagedType.I1)] public bool LogNecDsp;
[MarshalAs(UnmanagedType.I1)] public bool ShowExtraInfo;
[MarshalAs(UnmanagedType.I1)] public bool IndentCode;

View file

@ -25,6 +25,13 @@ public:
_pos += size;
}
void Delimiter(const char* str)
{
if(_pos > 0) {
Write(str, (uint16_t)strlen(str));
}
}
void Write(const char* str)
{
Write(str, (uint16_t)strlen(str));

View file

@ -14,6 +14,7 @@ namespace fs = std::experimental::filesystem;
string FolderUtilities::_homeFolder = "";
string FolderUtilities::_saveFolderOverride = "";
string FolderUtilities::_saveStateFolderOverride = "";
string FolderUtilities::_biosFolderOverride = "";
string FolderUtilities::_screenshotFolderOverride = "";
vector<string> FolderUtilities::_gameFolders = vector<string>();
@ -74,6 +75,18 @@ string FolderUtilities::GetSaveFolder()
return folder;
}
string FolderUtilities::GetBiosFolder()
{
string folder;
if(_biosFolderOverride.empty()) {
folder = CombinePath(GetHomeFolder(), "Bios");
} else {
folder = _biosFolderOverride;
}
CreateFolder(folder);
return folder;
}
string FolderUtilities::GetHdPackFolder()
{
string folder = CombinePath(GetHomeFolder(), "HdPacks");

View file

@ -9,6 +9,7 @@ private:
static string _homeFolder;
static string _saveFolderOverride;
static string _saveStateFolderOverride;
static string _biosFolderOverride;
static string _screenshotFolderOverride;
static vector<string> _gameFolders;
@ -22,6 +23,7 @@ public:
static vector<string> GetKnownGameFolders();
static string GetSaveFolder();
static string GetBiosFolder();
static string GetSaveStateFolder();
static string GetScreenshotFolder();
static string GetHdPackFolder();

View file

@ -123,6 +123,12 @@ string VirtualFile::GetSha1Hash()
return SHA1::GetHash(_data);
}
size_t VirtualFile::GetSize()
{
LoadFile();
return _data.size();
}
bool VirtualFile::ReadFile(vector<uint8_t>& out)
{
LoadFile();

View file

@ -31,6 +31,8 @@ public:
string GetFileName();
string GetSha1Hash();
size_t GetSize();
bool ReadFile(vector<uint8_t> &out);
bool ReadFile(std::stringstream &out);