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:
parent
7d1bd565a6
commit
5f65bad68c
|
@ -30,7 +30,7 @@ namespace DSP
|
||||||
//#define PRECISE_BACKLOG
|
//#define PRECISE_BACKLOG
|
||||||
|
|
||||||
// Returns false if the hash fails and the user hits "Yes"
|
// 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
|
struct DspRomHashes
|
||||||
{
|
{
|
||||||
|
@ -59,11 +59,10 @@ static bool VerifyRoms(const DSPCore& core)
|
||||||
{0x128ea7a2, 0xa4a575f5},
|
{0x128ea7a2, 0xa4a575f5},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const auto& state = core.DSPState();
|
|
||||||
const u32 hash_irom =
|
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 =
|
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;
|
int rom_idx = -1;
|
||||||
|
|
||||||
for (size_t i = 0; i < known_roms.size(); ++i)
|
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
|
class LLEAccelerator final : public Accelerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit LLEAccelerator(DSPCore& core) : m_core{core} {}
|
explicit LLEAccelerator(SDSP& dsp) : m_dsp{dsp} {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
|
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
|
||||||
void WriteMemory(u32 address, u8 value) override { Host::WriteHostMemory(value, 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:
|
private:
|
||||||
DSPCore& m_core;
|
SDSP& m_dsp;
|
||||||
};
|
};
|
||||||
|
|
||||||
SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
|
SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
|
||||||
|
@ -122,6 +121,288 @@ SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
|
||||||
|
|
||||||
SDSP::~SDSP() = default;
|
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()
|
DSPCore::DSPCore()
|
||||||
: m_dsp{*this}, m_dsp_interpreter{std::make_unique<Interpreter::Interpreter>(*this)}
|
: 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)
|
bool DSPCore::Initialize(const DSPInitOptions& opts)
|
||||||
{
|
{
|
||||||
m_dsp.step_counter = 0;
|
if (!m_dsp.Initialize(opts))
|
||||||
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();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
std::memset(&m_dsp.r, 0, sizeof(m_dsp.r));
|
m_init_hax = false;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Initialize JIT, if necessary
|
// Initialize JIT, if necessary
|
||||||
if (opts.core_type == DSPInitOptions::CoreType::JIT64)
|
if (opts.core_type == DSPInitOptions::CoreType::JIT64)
|
||||||
|
@ -195,9 +435,7 @@ void DSPCore::Shutdown()
|
||||||
m_core_state = State::Stopped;
|
m_core_state = State::Stopped;
|
||||||
|
|
||||||
m_dsp_jit.reset();
|
m_dsp_jit.reset();
|
||||||
|
m_dsp.Shutdown();
|
||||||
FreeMemoryPages();
|
|
||||||
|
|
||||||
m_dsp_cap.reset();
|
m_dsp_cap.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,10 +486,7 @@ void DSPCore::Step()
|
||||||
|
|
||||||
void DSPCore::Reset()
|
void DSPCore::Reset()
|
||||||
{
|
{
|
||||||
m_dsp.pc = DSP_RESET_VECTOR;
|
m_dsp.Reset();
|
||||||
|
|
||||||
std::fill(std::begin(m_dsp.r.wr), std::end(m_dsp.r.wr), 0xffff);
|
|
||||||
|
|
||||||
Analyzer::Analyze(m_dsp);
|
Analyzer::Analyze(m_dsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,185 +516,32 @@ State DSPCore::GetState() const
|
||||||
|
|
||||||
void DSPCore::SetException(ExceptionType exception)
|
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)
|
void DSPCore::SetExternalInterrupt(bool val)
|
||||||
{
|
{
|
||||||
m_dsp.external_interrupt_waiting = val;
|
m_dsp.SetExternalInterrupt(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore::CheckExternalInterrupt()
|
void DSPCore::CheckExternalInterrupt()
|
||||||
{
|
{
|
||||||
if (!m_dsp.IsSRFlagSet(SR_EXT_INT_ENABLE))
|
m_dsp.CheckExternalInterrupt();
|
||||||
return;
|
|
||||||
|
|
||||||
// Signal the SPU about new mail
|
|
||||||
SetException(ExceptionType::ExternalInterrupt);
|
|
||||||
|
|
||||||
m_dsp.cr &= ~CR_EXTERNAL_INT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore::CheckExceptions()
|
void DSPCore::CheckExceptions()
|
||||||
{
|
{
|
||||||
// Early out to skip the loop in the common case.
|
m_dsp.CheckExceptions();
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPCore::ReadRegister(size_t reg) const
|
u16 DSPCore::ReadRegister(size_t reg) const
|
||||||
{
|
{
|
||||||
switch (reg)
|
return m_dsp.ReadRegister(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore::WriteRegister(size_t reg, u16 val)
|
void DSPCore::WriteRegister(size_t reg, u16 val)
|
||||||
{
|
{
|
||||||
switch (reg)
|
m_dsp.WriteRegister(reg, val);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 DSPCore::PeekMailbox(Mailbox mailbox) const
|
u32 DSPCore::PeekMailbox(Mailbox mailbox) const
|
||||||
|
@ -509,46 +591,10 @@ bool DSPCore::IsJITCreated() const
|
||||||
|
|
||||||
void DSPCore::DoState(PointerWrap& p)
|
void DSPCore::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
p.Do(m_dsp.r);
|
m_dsp.DoState(p);
|
||||||
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);
|
|
||||||
p.Do(m_init_hax);
|
p.Do(m_init_hax);
|
||||||
|
|
||||||
if (m_dsp_jit)
|
if (m_dsp_jit)
|
||||||
m_dsp_jit->DoState(p);
|
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
|
} // namespace DSP
|
||||||
|
|
|
@ -274,6 +274,30 @@ struct DSP_Regs
|
||||||
} ac[2];
|
} 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
|
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
|
||||||
// should be moved here.
|
// should be moved here.
|
||||||
struct SDSP
|
struct SDSP
|
||||||
|
@ -287,6 +311,15 @@ struct SDSP
|
||||||
SDSP(SDSP&&) = delete;
|
SDSP(SDSP&&) = delete;
|
||||||
SDSP& operator=(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.
|
// Initializes the IFX registers.
|
||||||
void InitializeIFX();
|
void InitializeIFX();
|
||||||
|
|
||||||
|
@ -335,12 +368,34 @@ struct SDSP
|
||||||
// Whether or not the given flag is set in the SR register.
|
// Whether or not the given flag is set in the SR register.
|
||||||
bool IsSRFlagSet(u16 flag) const { return (r.sr & flag) != 0; }
|
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
|
// Stores a value into the specified stack
|
||||||
void StoreStack(StackRegister stack_reg, u16 val);
|
void StoreStack(StackRegister stack_reg, u16 val);
|
||||||
|
|
||||||
// Pops a value off of the specified stack
|
// Pops a value off of the specified stack
|
||||||
u16 PopStack(StackRegister stack_reg);
|
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{};
|
DSP_Regs r{};
|
||||||
u16 pc = 0;
|
u16 pc = 0;
|
||||||
|
|
||||||
|
@ -383,6 +438,8 @@ struct SDSP
|
||||||
u16* coef = nullptr;
|
u16* coef = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void FreeMemoryPages();
|
||||||
|
|
||||||
void DoDMA();
|
void DoDMA();
|
||||||
const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
||||||
const u8* DDMAOut(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;
|
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
|
enum class State
|
||||||
{
|
{
|
||||||
Stopped,
|
Stopped,
|
||||||
|
@ -527,8 +560,6 @@ public:
|
||||||
void SetInitHax(bool value) { m_init_hax = value; }
|
void SetInitHax(bool value) { m_init_hax = value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FreeMemoryPages();
|
|
||||||
|
|
||||||
SDSP m_dsp;
|
SDSP m_dsp;
|
||||||
DSPBreakpoints m_dsp_breakpoints;
|
DSPBreakpoints m_dsp_breakpoints;
|
||||||
State m_core_state = State::Stopped;
|
State m_core_state = State::Stopped;
|
||||||
|
|
Loading…
Reference in New Issue