DSP: Added support for DSP-1/2/3/4 games (LLE - requires bios file)
This commit is contained in:
parent
521df256fa
commit
c9405d7ba3
38 changed files with 1325 additions and 72 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
11
Core/BaseCoprocessor.h
Normal 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;
|
||||
};
|
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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,
|
||||
};
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
519
Core/NecDsp.cpp
Normal 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
64
Core/NecDsp.h
Normal 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
131
Core/NecDspDisUtils.cpp
Normal 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
13
Core/NecDspDisUtils.h
Normal 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
77
Core/NecDspTypes.h
Normal 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;
|
||||
};
|
36
Core/Ppu.cpp
36
Core/Ppu.cpp
|
@ -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>
|
||||
|
|
|
@ -252,6 +252,7 @@ public:
|
|||
uint16_t GetVblankStart();
|
||||
|
||||
PpuState GetState();
|
||||
void GetState(PpuState &state, bool returnPartialState);
|
||||
|
||||
bool ProcessEndOfScanline(uint16_t hClock);
|
||||
uint16_t GetLastScanline();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace Mesen.GUI.Config
|
|||
{
|
||||
public bool LogCpu;
|
||||
public bool LogSpc;
|
||||
public bool LogNecDsp;
|
||||
|
||||
public bool ShowByteCode;
|
||||
public bool ShowRegisters;
|
||||
|
|
|
@ -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;
|
||||
|
|
15
UI/Debugger/frmTraceLogger.Designer.cs
generated
15
UI/Debugger/frmTraceLogger.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
string GetFileName();
|
||||
string GetSha1Hash();
|
||||
|
||||
size_t GetSize();
|
||||
|
||||
bool ReadFile(vector<uint8_t> &out);
|
||||
bool ReadFile(std::stringstream &out);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue