diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index 013b76e..2035cbf 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -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::CreateCartridge(EmuSettings* settings, VirtualFile &romFile, VirtualFile &patchFile) +shared_ptr BaseCartridge::CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile) { if(romFile.IsValid()) { shared_ptr cart(new BaseCartridge()); @@ -38,7 +41,7 @@ shared_ptr 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(_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 += ""; 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("-----------------------------"); -} \ No newline at end of file +} + +NecDsp* BaseCartridge::GetDsp() +{ + return _necDsp; +} + +BaseCoprocessor * BaseCartridge::GetCoprocessor() +{ + return _coprocessor.get(); +} diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index 13842c7..8a6b0cc 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -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> _prgRomHandlers; vector> _saveRamHandlers; SnesCartInformation _cartInfo = {}; + unique_ptr _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 CreateCartridge(EmuSettings* settings, VirtualFile &romFile, VirtualFile &patchFile); + static shared_ptr 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; }; diff --git a/Core/BaseCoprocessor.h b/Core/BaseCoprocessor.h new file mode 100644 index 0000000..1459817 --- /dev/null +++ b/Core/BaseCoprocessor.h @@ -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; +}; \ No newline at end of file diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index 4b36306..8cbd4af 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -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 &breakpoints = _breakpoints[(int)category][(int)type]; for(size_t i = 0; i < breakpoints.size(); i++) { diff --git a/Core/CartTypes.h b/Core/CartTypes.h index a4ddb04..774cb03 100644 --- a/Core/CartTypes.h +++ b/Core/CartTypes.h @@ -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 }; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index 2039241..29440fb 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -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 cart = BaseCartridge::CreateCartridge(_settings.get(), romFile, patchFile); + shared_ptr 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(); + } } } diff --git a/Core/Console.h b/Core/Console.h index ce9de86..f93e372 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -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); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 7f80b13..88299f5 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -47,6 +47,7 @@ + @@ -78,6 +79,9 @@ + + + @@ -179,6 +183,8 @@ + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index a2cff28..01ed89f 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -290,6 +290,18 @@ SNES + + Debugger\Disassembler + + + SNES\Coprocessors + + + SNES\Coprocessors + + + SNES\Coprocessors + @@ -474,6 +486,10 @@ Debugger\Scripts + + + SNES\Coprocessors + @@ -509,5 +525,8 @@ {ca39cd9a-a95c-4b7a-b6d5-de41565dd8f6} + + {6d4d05d5-3ad3-4087-9be0-3fd9e461c3e0} + \ No newline at end of file diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index 0afbb7c..f924624 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -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, }; \ No newline at end of file diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 6abe610..37f19de 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -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) _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) _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) _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; diff --git a/Core/Debugger.h b/Core/Debugger.h index d273711..48c62de 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -36,7 +36,7 @@ private: shared_ptr _ppu; shared_ptr _spc; shared_ptr _memoryManager; - shared_ptr _baseCartridge; + shared_ptr _cart; shared_ptr _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); diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index 74def16..6ff0e59 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -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, shared_ptrGetSpc()->GetSpcRom(); _spcRomSize = Spc::SpcRomSize; + _necDspProgramRom = console->GetCartridge()->GetDsp() ? console->GetCartridge()->GetDsp()->DebugGetProgramRom() : nullptr; + _necDspProgramRomSize = console->GetCartridge()->GetDsp() ? console->GetCartridge()->GetDsp()->DebugGetProgramRomSize() : 0; + _prgCache = vector(_prgRomSize); _sramCache = vector(_sramSize); _wramCache = vector(_wramSize); _spcRamCache = vector(_spcRamSize); _spcRomCache = vector(_spcRomSize); + _necDspRomCache = vector(_necDspProgramRomSize); } void Disassembler::GetSource(AddressInfo &info, uint8_t **source, uint32_t &size, vector **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()) { diff --git a/Core/Disassembler.h b/Core/Disassembler.h index 8f827a8..ad1ad2b 100644 --- a/Core/Disassembler.h +++ b/Core/Disassembler.h @@ -30,6 +30,7 @@ private: vector _sramCache; vector _spcRamCache; vector _spcRomCache; + vector _necDspRomCache; SimpleLock _disassemblyLock; vector _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 **cache); diff --git a/Core/DisassemblyInfo.cpp b/Core/DisassemblyInfo.cpp index f25c98e..a817aa2 100644 --- a/Core/DisassemblyInfo.cpp +++ b/Core/DisassemblyInfo.cpp @@ -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; } } diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index f75e73c..c18b08a 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -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); diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index c07eb8d..bc16874 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -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]; } } diff --git a/Core/NecDsp.cpp b/Core/NecDsp.cpp new file mode 100644 index 0000000..5e15e8a --- /dev/null +++ b/Core/NecDsp.cpp @@ -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 &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 &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 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 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(_ram, 256); + s.StreamArray(_stack, 4); +} + diff --git a/Core/NecDsp.h b/Core/NecDsp.h new file mode 100644 index 0000000..3af94af --- /dev/null +++ b/Core/NecDsp.h @@ -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 &biosRom, uint16_t registerMask); + + static bool LoadBios(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &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; +}; \ No newline at end of file diff --git a/Core/NecDspDisUtils.cpp b/Core/NecDspDisUtils.cpp new file mode 100644 index 0000000..e31a796 --- /dev/null +++ b/Core/NecDspDisUtils.cpp @@ -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(""); 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(); +} diff --git a/Core/NecDspDisUtils.h b/Core/NecDspDisUtils.h new file mode 100644 index 0000000..aac2aeb --- /dev/null +++ b/Core/NecDspDisUtils.h @@ -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); +}; diff --git a/Core/NecDspTypes.h b/Core/NecDspTypes.h new file mode 100644 index 0000000..57de3b2 --- /dev/null +++ b/Core/NecDspTypes.h @@ -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; +}; diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 49edf5c..174246d 100644 --- a/Core/Ppu.cpp +++ b/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 diff --git a/Core/Ppu.h b/Core/Ppu.h index 5ee5cbc..924946f 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -252,6 +252,7 @@ public: uint16_t GetVblankStart(); PpuState GetState(); + void GetState(PpuState &state, bool returnPartialState); bool ProcessEndOfScanline(uint16_t hClock); uint16_t GetLastScanline(); diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index 12cf21a..4a34aa6 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -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 &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; diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index ebecb72..6cb5abf 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -16,6 +16,7 @@ struct TraceLoggerOptions { bool LogCpu; bool LogSpc; + bool LogNecDsp; bool ShowExtraInfo; bool IndentCode; @@ -75,8 +76,9 @@ private: vector _rowParts; vector _spcRowParts; + vector _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 void WriteValue(string &output, T value, RowPart& rowPart); @@ -115,6 +118,8 @@ public: TraceLogger(Debugger* debugger, shared_ptr console); ~TraceLogger(); + __forceinline bool IsCpuLogged(CpuType type) { return _logCpu[(int)type]; } + void Log(DebugState &state, DisassemblyInfo &disassemblyInfo); void Clear(); //void LogNonExec(OperationInfo& operationInfo); diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp index c0d3868..4d5eedc 100644 --- a/InteropDLL/DebugApiWrapper.cpp +++ b/InteropDLL/DebugApiWrapper.cpp @@ -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); } diff --git a/UI/Debugger/Config/TraceLoggerInfo.cs b/UI/Debugger/Config/TraceLoggerInfo.cs index 95d26f6..9c74787 100644 --- a/UI/Debugger/Config/TraceLoggerInfo.cs +++ b/UI/Debugger/Config/TraceLoggerInfo.cs @@ -47,6 +47,7 @@ namespace Mesen.GUI.Config { public bool LogCpu; public bool LogSpc; + public bool LogNecDsp; public bool ShowByteCode; public bool ShowRegisters; diff --git a/UI/Debugger/MemoryTools/frmMemoryTools.cs b/UI/Debugger/MemoryTools/frmMemoryTools.cs index a63f05d..3676a64 100644 --- a/UI/Debugger/MemoryTools/frmMemoryTools.cs +++ b/UI/Debugger/MemoryTools/frmMemoryTools.cs @@ -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; diff --git a/UI/Debugger/frmTraceLogger.Designer.cs b/UI/Debugger/frmTraceLogger.Designer.cs index 55677d9..3398f51 100644 --- a/UI/Debugger/frmTraceLogger.Designer.cs +++ b/UI/Debugger/frmTraceLogger.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/UI/Debugger/frmTraceLogger.cs b/UI/Debugger/frmTraceLogger.cs index 1fbba1c..7ddeaf1 100644 --- a/UI/Debugger/frmTraceLogger.cs +++ b/UI/Debugger/frmTraceLogger.cs @@ -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 _flags; public TraceLoggerStyleProvider(List 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 }; + } } } } diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index c54451a..e04bdf0 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -951,6 +951,9 @@ CG RAM (Palette) SPC RAM SPC ROM (IPL) + DSP-n - Program ROM + DSP-n - Data ROM + DSP-n - Data RAM Register diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 96b7afa..82388e6 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -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; diff --git a/Utilities/FastString.h b/Utilities/FastString.h index 26a3e7a..ae67946 100644 --- a/Utilities/FastString.h +++ b/Utilities/FastString.h @@ -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)); diff --git a/Utilities/FolderUtilities.cpp b/Utilities/FolderUtilities.cpp index bb4d4f3..213dd90 100644 --- a/Utilities/FolderUtilities.cpp +++ b/Utilities/FolderUtilities.cpp @@ -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 FolderUtilities::_gameFolders = vector(); @@ -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"); diff --git a/Utilities/FolderUtilities.h b/Utilities/FolderUtilities.h index 6d6d141..79a5089 100644 --- a/Utilities/FolderUtilities.h +++ b/Utilities/FolderUtilities.h @@ -9,6 +9,7 @@ private: static string _homeFolder; static string _saveFolderOverride; static string _saveStateFolderOverride; + static string _biosFolderOverride; static string _screenshotFolderOverride; static vector _gameFolders; @@ -22,6 +23,7 @@ public: static vector GetKnownGameFolders(); static string GetSaveFolder(); + static string GetBiosFolder(); static string GetSaveStateFolder(); static string GetScreenshotFolder(); static string GetHdPackFolder(); diff --git a/Utilities/VirtualFile.cpp b/Utilities/VirtualFile.cpp index 5ef4d73..67d11eb 100644 --- a/Utilities/VirtualFile.cpp +++ b/Utilities/VirtualFile.cpp @@ -123,6 +123,12 @@ string VirtualFile::GetSha1Hash() return SHA1::GetHash(_data); } +size_t VirtualFile::GetSize() +{ + LoadFile(); + return _data.size(); +} + bool VirtualFile::ReadFile(vector& out) { LoadFile(); diff --git a/Utilities/VirtualFile.h b/Utilities/VirtualFile.h index 590bf1c..fee79c5 100644 --- a/Utilities/VirtualFile.h +++ b/Utilities/VirtualFile.h @@ -31,6 +31,8 @@ public: string GetFileName(); string GetSha1Hash(); + size_t GetSize(); + bool ReadFile(vector &out); bool ReadFile(std::stringstream &out);