DSP: Migrate code that modifies m_dsp into SDSP itself

Localizes code that modifies m_dsp into the struct itself. This reduces
the overal coupling between DSPCore and SDSP by reducing access to its
member variables.

This commit is only code movement and has no functional changes.
This commit is contained in:
Lioncash 2020-12-22 17:09:47 -05:00
parent 7d1bd565a6
commit 5f65bad68c
2 changed files with 356 additions and 279 deletions

View file

@ -30,7 +30,7 @@ namespace DSP
//#define PRECISE_BACKLOG
// Returns false if the hash fails and the user hits "Yes"
static bool VerifyRoms(const DSPCore& core)
static bool VerifyRoms(const SDSP& dsp)
{
struct DspRomHashes
{
@ -59,11 +59,10 @@ static bool VerifyRoms(const DSPCore& core)
{0x128ea7a2, 0xa4a575f5},
}};
const auto& state = core.DSPState();
const u32 hash_irom =
Common::HashAdler32(reinterpret_cast<const u8*>(state.irom), DSP_IROM_BYTE_SIZE);
Common::HashAdler32(reinterpret_cast<const u8*>(dsp.irom), DSP_IROM_BYTE_SIZE);
const u32 hash_drom =
Common::HashAdler32(reinterpret_cast<const u8*>(state.coef), DSP_COEF_BYTE_SIZE);
Common::HashAdler32(reinterpret_cast<const u8*>(dsp.coef), DSP_COEF_BYTE_SIZE);
int rom_idx = -1;
for (size_t i = 0; i < known_roms.size(); ++i)
@ -105,15 +104,15 @@ static bool VerifyRoms(const DSPCore& core)
class LLEAccelerator final : public Accelerator
{
public:
explicit LLEAccelerator(DSPCore& core) : m_core{core} {}
explicit LLEAccelerator(SDSP& dsp) : m_dsp{dsp} {}
protected:
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
void WriteMemory(u32 address, u8 value) override { Host::WriteHostMemory(value, address); }
void OnEndException() override { m_core.SetException(ExceptionType::AcceleratorOverflow); }
void OnEndException() override { m_dsp.SetException(ExceptionType::AcceleratorOverflow); }
private:
DSPCore& m_core;
SDSP& m_dsp;
};
SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
@ -122,6 +121,288 @@ SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
SDSP::~SDSP() = default;
bool SDSP::Initialize(const DSPInitOptions& opts)
{
step_counter = 0;
accelerator = std::make_unique<LLEAccelerator>(*this);
irom = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IROM_BYTE_SIZE));
iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE));
dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE));
coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE));
std::memcpy(irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE);
std::memcpy(coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE);
// Try to load real ROM contents.
if (!VerifyRoms(*this))
{
FreeMemoryPages();
return false;
}
std::memset(&r, 0, sizeof(r));
std::fill(std::begin(reg_stack_ptrs), std::end(reg_stack_ptrs), 0);
for (auto& stack : reg_stacks)
std::fill(std::begin(stack), std::end(stack), 0);
// Fill IRAM with HALT opcodes.
std::fill(iram, iram + DSP_IRAM_SIZE, 0x0021);
// Just zero out DRAM.
std::fill(dram, dram + DSP_DRAM_SIZE, 0);
// Copied from a real console after the custom UCode has been loaded.
// These are the indexing wrapping registers.
std::fill(std::begin(r.wr), std::end(r.wr), 0xffff);
r.sr |= SR_INT_ENABLE;
r.sr |= SR_EXT_INT_ENABLE;
cr = 0x804;
InitializeIFX();
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
// in new ucodes.
Common::WriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
return true;
}
void SDSP::Reset()
{
pc = DSP_RESET_VECTOR;
std::fill(std::begin(r.wr), std::end(r.wr), 0xffff);
}
void SDSP::Shutdown()
{
FreeMemoryPages();
}
void SDSP::FreeMemoryPages()
{
Common::FreeMemoryPages(irom, DSP_IROM_BYTE_SIZE);
Common::FreeMemoryPages(iram, DSP_IRAM_BYTE_SIZE);
Common::FreeMemoryPages(dram, DSP_DRAM_BYTE_SIZE);
Common::FreeMemoryPages(coef, DSP_COEF_BYTE_SIZE);
irom = nullptr;
iram = nullptr;
dram = nullptr;
coef = nullptr;
}
void SDSP::SetException(ExceptionType exception)
{
exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
}
void SDSP::SetExternalInterrupt(bool val)
{
external_interrupt_waiting = val;
}
void SDSP::CheckExternalInterrupt()
{
if (!IsSRFlagSet(SR_EXT_INT_ENABLE))
return;
// Signal the SPU about new mail
SetException(ExceptionType::ExternalInterrupt);
cr &= ~CR_EXTERNAL_INT;
}
void SDSP::CheckExceptions()
{
// Early out to skip the loop in the common case.
if (exceptions == 0)
return;
for (int i = 7; i > 0; i--)
{
// Seems exp int are not masked by sr_int_enable
if ((exceptions & (1U << i)) != 0)
{
if (IsSRFlagSet(SR_INT_ENABLE) || i == static_cast<int>(ExceptionType::ExternalInterrupt))
{
// store pc and sr until RTI
StoreStack(StackRegister::Call, pc);
StoreStack(StackRegister::Data, r.sr);
pc = static_cast<u16>(i * 2);
exceptions &= ~(1 << i);
if (i == 7)
r.sr &= ~SR_EXT_INT_ENABLE;
else
r.sr &= ~SR_INT_ENABLE;
break;
}
else
{
#if defined(_DEBUG) || defined(DEBUGFAST)
ERROR_LOG_FMT(DSPLLE, "Firing exception {} failed", i);
#endif
}
}
}
}
u16 SDSP::ReadRegister(size_t reg) const
{
switch (reg)
{
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
return r.ar[reg - DSP_REG_AR0];
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
return r.ix[reg - DSP_REG_IX0];
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
return r.wr[reg - DSP_REG_WR0];
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
return r.st[reg - DSP_REG_ST0];
case DSP_REG_ACH0:
case DSP_REG_ACH1:
return r.ac[reg - DSP_REG_ACH0].h;
case DSP_REG_CR:
return r.cr;
case DSP_REG_SR:
return r.sr;
case DSP_REG_PRODL:
return r.prod.l;
case DSP_REG_PRODM:
return r.prod.m;
case DSP_REG_PRODH:
return r.prod.h;
case DSP_REG_PRODM2:
return r.prod.m2;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
return r.ax[reg - DSP_REG_AXL0].l;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
return r.ax[reg - DSP_REG_AXH0].h;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
return r.ac[reg - DSP_REG_ACL0].l;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
return r.ac[reg - DSP_REG_ACM0].m;
default:
ASSERT_MSG(DSP_CORE, 0, "cannot happen");
return 0;
}
}
void SDSP::WriteRegister(size_t reg, u16 val)
{
switch (reg)
{
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
r.ar[reg - DSP_REG_AR0] = val;
break;
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
r.ix[reg - DSP_REG_IX0] = val;
break;
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
r.wr[reg - DSP_REG_WR0] = val;
break;
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
r.st[reg - DSP_REG_ST0] = val;
break;
case DSP_REG_ACH0:
case DSP_REG_ACH1:
r.ac[reg - DSP_REG_ACH0].h = val;
break;
case DSP_REG_CR:
r.cr = val;
break;
case DSP_REG_SR:
r.sr = val;
break;
case DSP_REG_PRODL:
r.prod.l = val;
break;
case DSP_REG_PRODM:
r.prod.m = val;
break;
case DSP_REG_PRODH:
r.prod.h = val;
break;
case DSP_REG_PRODM2:
r.prod.m2 = val;
break;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
r.ax[reg - DSP_REG_AXL0].l = val;
break;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
r.ax[reg - DSP_REG_AXH0].h = val;
break;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
r.ac[reg - DSP_REG_ACL0].l = val;
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
r.ac[reg - DSP_REG_ACM0].m = val;
break;
}
}
void SDSP::DoState(PointerWrap& p)
{
p.Do(r);
p.Do(pc);
p.Do(cr);
p.Do(reg_stack_ptrs);
p.Do(exceptions);
p.Do(external_interrupt_waiting);
for (auto& stack : reg_stacks)
{
p.Do(stack);
}
p.Do(step_counter);
p.DoArray(ifx_regs);
accelerator->DoState(p);
p.Do(mbox[0]);
p.Do(mbox[1]);
Common::UnWriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
p.DoArray(iram, DSP_IRAM_SIZE);
Common::WriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
// TODO: This uses the wrong endianness (producing bad disassembly)
// and a bogus byte count (producing bad hashes)
if (p.GetMode() == PointerWrap::MODE_READ)
Host::CodeLoaded(m_dsp_core, reinterpret_cast<const u8*>(iram), DSP_IRAM_BYTE_SIZE);
p.DoArray(dram, DSP_DRAM_SIZE);
}
DSPCore::DSPCore()
: m_dsp{*this}, m_dsp_interpreter{std::make_unique<Interpreter::Interpreter>(*this)}
{
@ -131,51 +412,10 @@ DSPCore::~DSPCore() = default;
bool DSPCore::Initialize(const DSPInitOptions& opts)
{
m_dsp.step_counter = 0;
m_init_hax = false;
m_dsp.accelerator = std::make_unique<LLEAccelerator>(*this);
m_dsp.irom = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IROM_BYTE_SIZE));
m_dsp.iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE));
m_dsp.dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE));
m_dsp.coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE));
std::memcpy(m_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE);
std::memcpy(m_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE);
// Try to load real ROM contents.
if (!VerifyRoms(*this))
{
FreeMemoryPages();
if (!m_dsp.Initialize(opts))
return false;
}
std::memset(&m_dsp.r, 0, sizeof(m_dsp.r));
std::fill(std::begin(m_dsp.reg_stack_ptrs), std::end(m_dsp.reg_stack_ptrs), 0);
for (auto& stack : m_dsp.reg_stacks)
std::fill(std::begin(stack), std::end(stack), 0);
// Fill IRAM with HALT opcodes.
std::fill(m_dsp.iram, m_dsp.iram + DSP_IRAM_SIZE, 0x0021);
// Just zero out DRAM.
std::fill(m_dsp.dram, m_dsp.dram + DSP_DRAM_SIZE, 0);
// Copied from a real console after the custom UCode has been loaded.
// These are the indexing wrapping registers.
std::fill(std::begin(m_dsp.r.wr), std::end(m_dsp.r.wr), 0xffff);
m_dsp.r.sr |= SR_INT_ENABLE;
m_dsp.r.sr |= SR_EXT_INT_ENABLE;
m_dsp.cr = 0x804;
m_dsp.InitializeIFX();
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
// in new ucodes.
Common::WriteProtectMemory(m_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
m_init_hax = false;
// Initialize JIT, if necessary
if (opts.core_type == DSPInitOptions::CoreType::JIT64)
@ -195,9 +435,7 @@ void DSPCore::Shutdown()
m_core_state = State::Stopped;
m_dsp_jit.reset();
FreeMemoryPages();
m_dsp.Shutdown();
m_dsp_cap.reset();
}
@ -248,10 +486,7 @@ void DSPCore::Step()
void DSPCore::Reset()
{
m_dsp.pc = DSP_RESET_VECTOR;
std::fill(std::begin(m_dsp.r.wr), std::end(m_dsp.r.wr), 0xffff);
m_dsp.Reset();
Analyzer::Analyze(m_dsp);
}
@ -281,185 +516,32 @@ State DSPCore::GetState() const
void DSPCore::SetException(ExceptionType exception)
{
m_dsp.exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
m_dsp.SetException(exception);
}
void DSPCore::SetExternalInterrupt(bool val)
{
m_dsp.external_interrupt_waiting = val;
m_dsp.SetExternalInterrupt(val);
}
void DSPCore::CheckExternalInterrupt()
{
if (!m_dsp.IsSRFlagSet(SR_EXT_INT_ENABLE))
return;
// Signal the SPU about new mail
SetException(ExceptionType::ExternalInterrupt);
m_dsp.cr &= ~CR_EXTERNAL_INT;
m_dsp.CheckExternalInterrupt();
}
void DSPCore::CheckExceptions()
{
// Early out to skip the loop in the common case.
if (m_dsp.exceptions == 0)
return;
for (int i = 7; i > 0; i--)
{
// Seems exp int are not masked by sr_int_enable
if ((m_dsp.exceptions & (1U << i)) != 0)
{
if (m_dsp.IsSRFlagSet(SR_INT_ENABLE) ||
i == static_cast<int>(ExceptionType::ExternalInterrupt))
{
// store pc and sr until RTI
m_dsp.StoreStack(StackRegister::Call, m_dsp.pc);
m_dsp.StoreStack(StackRegister::Data, m_dsp.r.sr);
m_dsp.pc = static_cast<u16>(i * 2);
m_dsp.exceptions &= ~(1 << i);
if (i == 7)
m_dsp.r.sr &= ~SR_EXT_INT_ENABLE;
else
m_dsp.r.sr &= ~SR_INT_ENABLE;
break;
}
else
{
#if defined(_DEBUG) || defined(DEBUGFAST)
ERROR_LOG_FMT(DSPLLE, "Firing exception {} failed", i);
#endif
}
}
}
m_dsp.CheckExceptions();
}
u16 DSPCore::ReadRegister(size_t reg) const
{
switch (reg)
{
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
return m_dsp.r.ar[reg - DSP_REG_AR0];
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
return m_dsp.r.ix[reg - DSP_REG_IX0];
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
return m_dsp.r.wr[reg - DSP_REG_WR0];
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
return m_dsp.r.st[reg - DSP_REG_ST0];
case DSP_REG_ACH0:
case DSP_REG_ACH1:
return m_dsp.r.ac[reg - DSP_REG_ACH0].h;
case DSP_REG_CR:
return m_dsp.r.cr;
case DSP_REG_SR:
return m_dsp.r.sr;
case DSP_REG_PRODL:
return m_dsp.r.prod.l;
case DSP_REG_PRODM:
return m_dsp.r.prod.m;
case DSP_REG_PRODH:
return m_dsp.r.prod.h;
case DSP_REG_PRODM2:
return m_dsp.r.prod.m2;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
return m_dsp.r.ax[reg - DSP_REG_AXL0].l;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
return m_dsp.r.ax[reg - DSP_REG_AXH0].h;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
return m_dsp.r.ac[reg - DSP_REG_ACL0].l;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
return m_dsp.r.ac[reg - DSP_REG_ACM0].m;
default:
ASSERT_MSG(DSP_CORE, 0, "cannot happen");
return 0;
}
return m_dsp.ReadRegister(reg);
}
void DSPCore::WriteRegister(size_t reg, u16 val)
{
switch (reg)
{
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
m_dsp.r.ar[reg - DSP_REG_AR0] = val;
break;
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
m_dsp.r.ix[reg - DSP_REG_IX0] = val;
break;
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
m_dsp.r.wr[reg - DSP_REG_WR0] = val;
break;
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
m_dsp.r.st[reg - DSP_REG_ST0] = val;
break;
case DSP_REG_ACH0:
case DSP_REG_ACH1:
m_dsp.r.ac[reg - DSP_REG_ACH0].h = val;
break;
case DSP_REG_CR:
m_dsp.r.cr = val;
break;
case DSP_REG_SR:
m_dsp.r.sr = val;
break;
case DSP_REG_PRODL:
m_dsp.r.prod.l = val;
break;
case DSP_REG_PRODM:
m_dsp.r.prod.m = val;
break;
case DSP_REG_PRODH:
m_dsp.r.prod.h = val;
break;
case DSP_REG_PRODM2:
m_dsp.r.prod.m2 = val;
break;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
m_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
break;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
m_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
break;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
m_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
m_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
break;
}
m_dsp.WriteRegister(reg, val);
}
u32 DSPCore::PeekMailbox(Mailbox mailbox) const
@ -509,46 +591,10 @@ bool DSPCore::IsJITCreated() const
void DSPCore::DoState(PointerWrap& p)
{
p.Do(m_dsp.r);
p.Do(m_dsp.pc);
p.Do(m_dsp.cr);
p.Do(m_dsp.reg_stack_ptrs);
p.Do(m_dsp.exceptions);
p.Do(m_dsp.external_interrupt_waiting);
for (auto& stack : m_dsp.reg_stacks)
{
p.Do(stack);
}
p.Do(m_dsp.step_counter);
p.DoArray(m_dsp.ifx_regs);
m_dsp.accelerator->DoState(p);
p.Do(m_dsp.mbox[0]);
p.Do(m_dsp.mbox[1]);
Common::UnWriteProtectMemory(m_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
p.DoArray(m_dsp.iram, DSP_IRAM_SIZE);
Common::WriteProtectMemory(m_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
// TODO: This uses the wrong endianness (producing bad disassembly)
// and a bogus byte count (producing bad hashes)
if (p.GetMode() == PointerWrap::MODE_READ)
Host::CodeLoaded(*this, reinterpret_cast<const u8*>(m_dsp.iram), DSP_IRAM_BYTE_SIZE);
p.DoArray(m_dsp.dram, DSP_DRAM_SIZE);
m_dsp.DoState(p);
p.Do(m_init_hax);
if (m_dsp_jit)
m_dsp_jit->DoState(p);
}
void DSPCore::FreeMemoryPages()
{
Common::FreeMemoryPages(m_dsp.irom, DSP_IROM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.iram, DSP_IRAM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.dram, DSP_DRAM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.coef, DSP_COEF_BYTE_SIZE);
m_dsp.irom = nullptr;
m_dsp.iram = nullptr;
m_dsp.dram = nullptr;
m_dsp.coef = nullptr;
}
} // namespace DSP

View file

@ -274,6 +274,30 @@ struct DSP_Regs
} ac[2];
};
struct DSPInitOptions
{
// DSP IROM blob, which is where the DSP boots from. Embedded into the DSP.
std::array<u16, DSP_IROM_SIZE> irom_contents;
// DSP DROM blob, which contains resampling coefficients.
std::array<u16, DSP_COEF_SIZE> coef_contents;
// Core used to emulate the DSP.
// Default: JIT64.
enum class CoreType
{
Interpreter,
JIT64,
};
CoreType core_type = CoreType::JIT64;
// Optional capture logger used to log internal DSP data transfers.
// Default: dummy implementation, does nothing.
DSPCaptureLogger* capture_logger;
DSPInitOptions() : capture_logger(new DefaultDSPCaptureLogger()) {}
};
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
// should be moved here.
struct SDSP
@ -287,6 +311,15 @@ struct SDSP
SDSP(SDSP&&) = delete;
SDSP& operator=(SDSP&&) = delete;
// Initializes overall state.
bool Initialize(const DSPInitOptions& opts);
// Shuts down any necessary DSP state.
void Shutdown();
// Resets DSP state as if the reset exception vector has been taken.
void Reset();
// Initializes the IFX registers.
void InitializeIFX();
@ -335,12 +368,34 @@ struct SDSP
// Whether or not the given flag is set in the SR register.
bool IsSRFlagSet(u16 flag) const { return (r.sr & flag) != 0; }
// Indicates that a particular exception has occurred
// and sets a flag in the pending exception register.
void SetException(ExceptionType exception);
// Checks if any exceptions occurred an updates the DSP state as appropriate.
void CheckExceptions();
// Notify that an external interrupt is pending (used by thread mode)
void SetExternalInterrupt(bool val);
// Coming from the CPU
void CheckExternalInterrupt();
// Stores a value into the specified stack
void StoreStack(StackRegister stack_reg, u16 val);
// Pops a value off of the specified stack
u16 PopStack(StackRegister stack_reg);
// Reads the current value from a particular register.
u16 ReadRegister(size_t reg) const;
// Writes a value to a given register.
void WriteRegister(size_t reg, u16 val);
// Saves and loads any necessary state.
void DoState(PointerWrap& p);
DSP_Regs r{};
u16 pc = 0;
@ -383,6 +438,8 @@ struct SDSP
u16* coef = nullptr;
private:
void FreeMemoryPages();
void DoDMA();
const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
const u8* DDMAOut(u16 dsp_addr, u32 addr, u32 size);
@ -394,30 +451,6 @@ private:
DSPCore& m_dsp_core;
};
struct DSPInitOptions
{
// DSP IROM blob, which is where the DSP boots from. Embedded into the DSP.
std::array<u16, DSP_IROM_SIZE> irom_contents;
// DSP DROM blob, which contains resampling coefficients.
std::array<u16, DSP_COEF_SIZE> coef_contents;
// Core used to emulate the DSP.
// Default: JIT64.
enum class CoreType
{
Interpreter,
JIT64,
};
CoreType core_type = CoreType::JIT64;
// Optional capture logger used to log internal DSP data transfers.
// Default: dummy implementation, does nothing.
DSPCaptureLogger* capture_logger;
DSPInitOptions() : capture_logger(new DefaultDSPCaptureLogger()) {}
};
enum class State
{
Stopped,
@ -527,8 +560,6 @@ public:
void SetInitHax(bool value) { m_init_hax = value; }
private:
void FreeMemoryPages();
SDSP m_dsp;
DSPBreakpoints m_dsp_breakpoints;
State m_core_state = State::Stopped;