Large diffs are not rendered by default.

@@ -4,144 +4,248 @@

#pragma once

#include <array>
#include <cstddef>

#include "Core/DSP/DSPCommon.h"
#include "Core/DSP/DSPCore.h"

namespace DSP::Interpreter
{
void Step();

// See: DspIntBranch.cpp
void HandleLoop();

// If these simply return the same number of cycles as was passed into them,
// chances are that the DSP is halted.
// The difference between them is that the debug one obeys breakpoints.
int RunCyclesThread(int cycles);
int RunCycles(int cycles);
int RunCyclesDebug(int cycles);

void WriteCR(u16 val);
u16 ReadCR();

// All the opcode functions.
void abs(UDSPInstruction opc);
void add(UDSPInstruction opc);
void addarn(UDSPInstruction opc);
void addax(UDSPInstruction opc);
void addaxl(UDSPInstruction opc);
void addi(UDSPInstruction opc);
void addis(UDSPInstruction opc);
void addp(UDSPInstruction opc);
void addpaxz(UDSPInstruction opc);
void addr(UDSPInstruction opc);
void andc(UDSPInstruction opc);
void andcf(UDSPInstruction opc);
void andf(UDSPInstruction opc);
void andi(UDSPInstruction opc);
void andr(UDSPInstruction opc);
void asl(UDSPInstruction opc);
void asr(UDSPInstruction opc);
void asr16(UDSPInstruction opc);
void asrn(UDSPInstruction opc);
void asrnr(UDSPInstruction opc);
void asrnrx(UDSPInstruction opc);
void bloop(UDSPInstruction opc);
void bloopi(UDSPInstruction opc);
void call(UDSPInstruction opc);
void callr(UDSPInstruction opc);
void clr(UDSPInstruction opc);
void clrl(UDSPInstruction opc);
void clrp(UDSPInstruction opc);
void cmp(UDSPInstruction opc);
void cmpar(UDSPInstruction opc);
void cmpi(UDSPInstruction opc);
void cmpis(UDSPInstruction opc);
void dar(UDSPInstruction opc);
void dec(UDSPInstruction opc);
void decm(UDSPInstruction opc);
void halt(UDSPInstruction opc);
void iar(UDSPInstruction opc);
void ifcc(UDSPInstruction opc);
void ilrr(UDSPInstruction opc);
void ilrrd(UDSPInstruction opc);
void ilrri(UDSPInstruction opc);
void ilrrn(UDSPInstruction opc);
void inc(UDSPInstruction opc);
void incm(UDSPInstruction opc);
void jcc(UDSPInstruction opc);
void jmprcc(UDSPInstruction opc);
void loop(UDSPInstruction opc);
void loopi(UDSPInstruction opc);
void lr(UDSPInstruction opc);
void lri(UDSPInstruction opc);
void lris(UDSPInstruction opc);
void lrr(UDSPInstruction opc);
void lrrd(UDSPInstruction opc);
void lrri(UDSPInstruction opc);
void lrrn(UDSPInstruction opc);
void lrs(UDSPInstruction opc);
void lsl(UDSPInstruction opc);
void lsl16(UDSPInstruction opc);
void lsr(UDSPInstruction opc);
void lsr16(UDSPInstruction opc);
void lsrn(UDSPInstruction opc);
void lsrnr(UDSPInstruction opc);
void lsrnrx(UDSPInstruction opc);
void madd(UDSPInstruction opc);
void maddc(UDSPInstruction opc);
void maddx(UDSPInstruction opc);
void mov(UDSPInstruction opc);
void movax(UDSPInstruction opc);
void movnp(UDSPInstruction opc);
void movp(UDSPInstruction opc);
void movpz(UDSPInstruction opc);
void movr(UDSPInstruction opc);
void mrr(UDSPInstruction opc);
void msub(UDSPInstruction opc);
void msubc(UDSPInstruction opc);
void msubx(UDSPInstruction opc);
void mul(UDSPInstruction opc);
void mulac(UDSPInstruction opc);
void mulaxh(UDSPInstruction opc);
void mulc(UDSPInstruction opc);
void mulcac(UDSPInstruction opc);
void mulcmv(UDSPInstruction opc);
void mulcmvz(UDSPInstruction opc);
void mulmv(UDSPInstruction opc);
void mulmvz(UDSPInstruction opc);
void mulx(UDSPInstruction opc);
void mulxac(UDSPInstruction opc);
void mulxmv(UDSPInstruction opc);
void mulxmvz(UDSPInstruction opc);
void neg(UDSPInstruction opc);
void nop(UDSPInstruction opc);
void notc(UDSPInstruction opc);
void nx(UDSPInstruction opc);
void orc(UDSPInstruction opc);
void ori(UDSPInstruction opc);
void orr(UDSPInstruction opc);
void ret(UDSPInstruction opc);
void rti(UDSPInstruction opc);
void sbclr(UDSPInstruction opc);
void sbset(UDSPInstruction opc);
void si(UDSPInstruction opc);
void sr(UDSPInstruction opc);
void srbith(UDSPInstruction opc);
void srr(UDSPInstruction opc);
void srrd(UDSPInstruction opc);
void srri(UDSPInstruction opc);
void srrn(UDSPInstruction opc);
void srs(UDSPInstruction opc);
void sub(UDSPInstruction opc);
void subarn(UDSPInstruction opc);
void subax(UDSPInstruction opc);
void subp(UDSPInstruction opc);
void subr(UDSPInstruction opc);
void tst(UDSPInstruction opc);
void tstaxh(UDSPInstruction opc);
void tstprod(UDSPInstruction opc);
void xorc(UDSPInstruction opc);
void xori(UDSPInstruction opc);
void xorr(UDSPInstruction opc);
class Interpreter
{
public:
explicit Interpreter(DSPCore& dsp);
~Interpreter();

Interpreter(const Interpreter&) = delete;
Interpreter& operator=(const Interpreter&) = delete;

Interpreter(Interpreter&&) = delete;
Interpreter& operator=(Interpreter&&) = delete;

void Step();

// If these simply return the same number of cycles as was passed into them,
// chances are that the DSP is halted.
// The difference between them is that the debug one obeys breakpoints.
int RunCyclesThread(int cycles);
int RunCycles(int cycles);
int RunCyclesDebug(int cycles);

void WriteCR(u16 val);
u16 ReadCR();

void SetSRFlag(u16 flag);
bool IsSRFlagSet(u16 flag) const;

void ApplyWriteBackLog();

// All the opcode functions.
void abs(UDSPInstruction opc);
void add(UDSPInstruction opc);
void addarn(UDSPInstruction opc);
void addax(UDSPInstruction opc);
void addaxl(UDSPInstruction opc);
void addi(UDSPInstruction opc);
void addis(UDSPInstruction opc);
void addp(UDSPInstruction opc);
void addpaxz(UDSPInstruction opc);
void addr(UDSPInstruction opc);
void andc(UDSPInstruction opc);
void andcf(UDSPInstruction opc);
void andf(UDSPInstruction opc);
void andi(UDSPInstruction opc);
void andr(UDSPInstruction opc);
void asl(UDSPInstruction opc);
void asr(UDSPInstruction opc);
void asr16(UDSPInstruction opc);
void asrn(UDSPInstruction opc);
void asrnr(UDSPInstruction opc);
void asrnrx(UDSPInstruction opc);
void bloop(UDSPInstruction opc);
void bloopi(UDSPInstruction opc);
void call(UDSPInstruction opc);
void callr(UDSPInstruction opc);
void clr(UDSPInstruction opc);
void clrl(UDSPInstruction opc);
void clrp(UDSPInstruction opc);
void cmp(UDSPInstruction opc);
void cmpar(UDSPInstruction opc);
void cmpi(UDSPInstruction opc);
void cmpis(UDSPInstruction opc);
void dar(UDSPInstruction opc);
void dec(UDSPInstruction opc);
void decm(UDSPInstruction opc);
void halt(UDSPInstruction opc);
void iar(UDSPInstruction opc);
void ifcc(UDSPInstruction opc);
void ilrr(UDSPInstruction opc);
void ilrrd(UDSPInstruction opc);
void ilrri(UDSPInstruction opc);
void ilrrn(UDSPInstruction opc);
void inc(UDSPInstruction opc);
void incm(UDSPInstruction opc);
void jcc(UDSPInstruction opc);
void jmprcc(UDSPInstruction opc);
void loop(UDSPInstruction opc);
void loopi(UDSPInstruction opc);
void lr(UDSPInstruction opc);
void lri(UDSPInstruction opc);
void lris(UDSPInstruction opc);
void lrr(UDSPInstruction opc);
void lrrd(UDSPInstruction opc);
void lrri(UDSPInstruction opc);
void lrrn(UDSPInstruction opc);
void lrs(UDSPInstruction opc);
void lsl(UDSPInstruction opc);
void lsl16(UDSPInstruction opc);
void lsr(UDSPInstruction opc);
void lsr16(UDSPInstruction opc);
void lsrn(UDSPInstruction opc);
void lsrnr(UDSPInstruction opc);
void lsrnrx(UDSPInstruction opc);
void madd(UDSPInstruction opc);
void maddc(UDSPInstruction opc);
void maddx(UDSPInstruction opc);
void mov(UDSPInstruction opc);
void movax(UDSPInstruction opc);
void movnp(UDSPInstruction opc);
void movp(UDSPInstruction opc);
void movpz(UDSPInstruction opc);
void movr(UDSPInstruction opc);
void mrr(UDSPInstruction opc);
void msub(UDSPInstruction opc);
void msubc(UDSPInstruction opc);
void msubx(UDSPInstruction opc);
void mul(UDSPInstruction opc);
void mulac(UDSPInstruction opc);
void mulaxh(UDSPInstruction opc);
void mulc(UDSPInstruction opc);
void mulcac(UDSPInstruction opc);
void mulcmv(UDSPInstruction opc);
void mulcmvz(UDSPInstruction opc);
void mulmv(UDSPInstruction opc);
void mulmvz(UDSPInstruction opc);
void mulx(UDSPInstruction opc);
void mulxac(UDSPInstruction opc);
void mulxmv(UDSPInstruction opc);
void mulxmvz(UDSPInstruction opc);
void neg(UDSPInstruction opc);
void nop(UDSPInstruction opc);
void notc(UDSPInstruction opc);
void nx(UDSPInstruction opc);
void orc(UDSPInstruction opc);
void ori(UDSPInstruction opc);
void orr(UDSPInstruction opc);
void ret(UDSPInstruction opc);
void rti(UDSPInstruction opc);
void sbclr(UDSPInstruction opc);
void sbset(UDSPInstruction opc);
void si(UDSPInstruction opc);
void sr(UDSPInstruction opc);
void srbith(UDSPInstruction opc);
void srr(UDSPInstruction opc);
void srrd(UDSPInstruction opc);
void srri(UDSPInstruction opc);
void srrn(UDSPInstruction opc);
void srs(UDSPInstruction opc);
void sub(UDSPInstruction opc);
void subarn(UDSPInstruction opc);
void subax(UDSPInstruction opc);
void subp(UDSPInstruction opc);
void subr(UDSPInstruction opc);
void tst(UDSPInstruction opc);
void tstaxh(UDSPInstruction opc);
void tstprod(UDSPInstruction opc);
void xorc(UDSPInstruction opc);
void xori(UDSPInstruction opc);
void xorr(UDSPInstruction opc);

// Extended ops
void l(UDSPInstruction opc);
void ln(UDSPInstruction opc);
void ls(UDSPInstruction opc);
void lsn(UDSPInstruction opc);
void lsm(UDSPInstruction opc);
void lsnm(UDSPInstruction opc);
void sl(UDSPInstruction opc);
void sln(UDSPInstruction opc);
void slm(UDSPInstruction opc);
void slnm(UDSPInstruction opc);
void s(UDSPInstruction opc);
void sn(UDSPInstruction opc);
void ld(UDSPInstruction opc);
void ldax(UDSPInstruction opc);
void ldn(UDSPInstruction opc);
void ldaxn(UDSPInstruction opc);
void ldm(UDSPInstruction opc);
void ldaxm(UDSPInstruction opc);
void ldnm(UDSPInstruction opc);
void ldaxnm(UDSPInstruction opc);
void mv(UDSPInstruction opc);
void dr(UDSPInstruction opc);
void ir(UDSPInstruction opc);
void nr(UDSPInstruction opc);
void nop_ext(UDSPInstruction opc);

private:
void ExecuteInstruction(UDSPInstruction inst);

bool CheckCondition(u8 condition) const;

// See: DspIntBranch.cpp
void HandleLoop();

u16 IncrementAddressRegister(u16 reg) const;
u16 DecrementAddressRegister(u16 reg) const;

u16 IncreaseAddressRegister(u16 reg, s16 ix_) const;
u16 DecreaseAddressRegister(u16 reg, s16 ix_) const;

s32 GetLongACX(s32 reg) const;
s16 GetAXLow(s32 reg) const;
s16 GetAXHigh(s32 reg) const;

s64 GetLongAcc(s32 reg) const;
void SetLongAcc(s32 reg, s64 value);
s16 GetAccLow(s32 reg) const;
s16 GetAccMid(s32 reg) const;
s16 GetAccHigh(s32 reg) const;

s64 GetLongProduct() const;
s64 GetLongProductRounded() const;
void SetLongProduct(s64 value);

s64 GetMultiplyProduct(u16 a, u16 b, u8 sign = 0) const;
s64 Multiply(u16 a, u16 b, u8 sign = 0) const;
s64 MultiplyAdd(u16 a, u16 b, u8 sign = 0) const;
s64 MultiplySub(u16 a, u16 b, u8 sign = 0) const;
s64 MultiplyMulX(u8 axh0, u8 axh1, u16 val1, u16 val2) const;

void UpdateSR16(s16 value, bool carry = false, bool overflow = false, bool over_s32 = false);
void UpdateSR64(s64 value, bool carry = false, bool overflow = false);
void UpdateSRLogicZero(bool value);

u16 OpReadRegister(int reg_);
u16 OpReadRegisterAndSaturate(int reg) const;
void OpWriteRegister(int reg_, u16 val);

void ConditionalExtendAccum(int reg);

// The ext ops are calculated in parallel with the actual op. That means that
// both the main op and the ext op see the same register state as input. The
// output is simple as long as the main and ext ops don't change the same
// register. If they do the output is the bitwise OR of the result of both the
// main and ext ops.
void WriteToBackLog(int i, int idx, u16 value);
void ZeroWriteBackLog();
void ZeroWriteBackLogPreserveAcc(u8 acc);

DSPCore& m_dsp_core;

static constexpr size_t WRITEBACK_LOG_SIZE = 5;
std::array<u16, WRITEBACK_LOG_SIZE> m_write_back_log{};
std::array<int, WRITEBACK_LOG_SIZE> m_write_back_log_idx{-1, -1, -1, -1, -1};
};
} // namespace DSP::Interpreter
@@ -12,10 +12,10 @@ namespace DSP::JIT
{
DSPEmitter::~DSPEmitter() = default;

std::unique_ptr<DSPEmitter> CreateDSPEmitter()
std::unique_ptr<DSPEmitter> CreateDSPEmitter([[maybe_unused]] DSPCore& dsp)
{
#if defined(_M_X86) || defined(_M_X86_64)
return std::make_unique<x64::DSPEmitter>();
return std::make_unique<x64::DSPEmitter>(dsp);
#else
return std::make_unique<DSPEmitterNull>();
#endif
@@ -10,6 +10,11 @@

class PointerWrap;

namespace DSP
{
class DSPCore;
}

namespace DSP::JIT
{
class DSPEmitter
@@ -31,5 +36,5 @@ class DSPEmitterNull final : public DSPEmitter
void DoState(PointerWrap&) override {}
};

std::unique_ptr<DSPEmitter> CreateDSPEmitter();
std::unique_ptr<DSPEmitter> CreateDSPEmitter(DSPCore& dsp);
} // namespace DSP::JIT
@@ -17,9 +17,9 @@
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntTables.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Core/DSP/Jit/x64/DSPJitTables.h"

using namespace Gen;
@@ -30,9 +30,9 @@ constexpr size_t COMPILED_CODE_SIZE = 2097152;
constexpr size_t MAX_BLOCK_SIZE = 250;
constexpr u16 DSP_IDLE_SKIP_CYCLES = 0x1000;

DSPEmitter::DSPEmitter()
DSPEmitter::DSPEmitter(DSPCore& dsp)
: m_compile_status_register{SR_INT_ENABLE | SR_EXT_INT_ENABLE}, m_blocks(MAX_BLOCKS),
m_block_size(MAX_BLOCKS), m_block_links(MAX_BLOCKS)
m_block_size(MAX_BLOCKS), m_block_links(MAX_BLOCKS), m_dsp_core{dsp}
{
x64::InitInstructionTables();
AllocCodeSpace(COMPILED_CODE_SIZE);
@@ -51,18 +51,18 @@ DSPEmitter::~DSPEmitter()

u16 DSPEmitter::RunCycles(u16 cycles)
{
if (g_dsp.external_interrupt_waiting)
if (m_dsp_core.DSPState().external_interrupt_waiting)
{
DSPCore_CheckExternalInterrupt();
DSPCore_CheckExceptions();
DSPCore_SetExternalInterrupt(false);
m_dsp_core.CheckExternalInterrupt();
m_dsp_core.CheckExceptions();
m_dsp_core.SetExternalInterrupt(false);
}

m_cycles_left = cycles;
auto exec_addr = (DSPCompiledCode)m_enter_dispatcher;
exec_addr();

if (g_dsp.reset_dspjit_codespace)
if (m_dsp_core.DSPState().reset_dspjit_codespace)
ClearIRAMandDSPJITCodespaceReset();

return m_cycles_left;
@@ -82,7 +82,7 @@ void DSPEmitter::ClearIRAM()
m_block_size[i] = 0;
m_unresolved_jumps[i].clear();
}
g_dsp.reset_dspjit_codespace = true;
m_dsp_core.DSPState().reset_dspjit_codespace = true;
}

void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
@@ -98,7 +98,12 @@ void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
m_block_size[i] = 0;
m_unresolved_jumps[i].clear();
}
g_dsp.reset_dspjit_codespace = false;
m_dsp_core.DSPState().reset_dspjit_codespace = false;
}

static void CheckExceptionsThunk(DSPCore& dsp)
{
dsp.CheckExceptions();
}

// Must go out of block if exception is detected
@@ -112,7 +117,7 @@ void DSPEmitter::checkExceptions(u32 retval)

DSPJitRegCache c(m_gpr);
m_gpr.SaveRegs();
ABI_CallFunction(DSPCore_CheckExceptions);
ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core);
MOV(32, R(EAX), Imm32(retval));
JMP(m_return_dispatcher, true);
m_gpr.LoadRegs(false);
@@ -128,6 +133,11 @@ bool DSPEmitter::FlagsNeeded() const
return !(flags & Analyzer::CODE_START_OF_INST) || (flags & Analyzer::CODE_UPDATE_SR);
}

static void FallbackThunk(Interpreter::Interpreter& interpreter, UDSPInstruction inst)
{
(interpreter.*Interpreter::GetOp(inst))(inst);
}

void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
{
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
@@ -146,10 +156,20 @@ void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)

m_gpr.PushRegs();
ASSERT_MSG(DSPLLE, interpreter_function != nullptr, "No function for %04x", inst);
ABI_CallFunctionC16(interpreter_function, inst);
ABI_CallFunctionPC(FallbackThunk, &m_dsp_core.GetInterpreter(), inst);
m_gpr.PopRegs();
}

static void FallbackExtThunk(Interpreter::Interpreter& interpreter, UDSPInstruction inst)
{
(interpreter.*Interpreter::GetExtOp(inst))(inst);
}

static void ApplyWriteBackLogThunk(Interpreter::Interpreter& interpreter)
{
interpreter.ApplyWriteBackLog();
}

void DSPEmitter::EmitInstruction(UDSPInstruction inst)
{
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
@@ -168,10 +188,8 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
else
{
// Fall back to interpreter
const auto interpreter_function = Interpreter::GetExtOp(inst);

m_gpr.PushRegs();
ABI_CallFunctionC16(interpreter_function, inst);
ABI_CallFunctionPC(FallbackExtThunk, &m_dsp_core.GetInterpreter(), inst);
m_gpr.PopRegs();
INFO_LOG_FMT(DSPLLE, "Instruction not JITed(ext part): {:04x}", inst);
ext_is_jit = false;
@@ -198,7 +216,7 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
// need to call the online cleanup function because
// the writeBackLog gets populated at runtime
m_gpr.PushRegs();
ABI_CallFunction(ApplyWriteBackLog);
ABI_CallFunctionP(ApplyWriteBackLogThunk, &m_dsp_core.GetInterpreter());
m_gpr.PopRegs();
}
else
@@ -229,7 +247,7 @@ void DSPEmitter::Compile(u16 start_addr)
if (Analyzer::GetCodeFlags(m_compile_pc) & Analyzer::CODE_CHECK_INT)
checkExceptions(m_block_size[start_addr]);

UDSPInstruction inst = dsp_imem_read(m_compile_pc);
const UDSPInstruction inst = m_dsp_core.DSPState().ReadIMEM(m_compile_pc);
const DSPOPCTemplate* opcode = GetOpTemplate(inst);

EmitInstruction(inst);
@@ -377,7 +395,7 @@ void DSPEmitter::Compile(u16 start_addr)

void DSPEmitter::CompileCurrent(DSPEmitter& emitter)
{
emitter.Compile(g_dsp.pc);
emitter.Compile(emitter.m_dsp_core.DSPState().pc);

bool retry = true;

@@ -414,7 +432,7 @@ void DSPEmitter::CompileDispatcher()
BitSet32 registers_used = ABI_ALL_CALLEE_SAVED & BitSet32(0xffff);
ABI_PushRegistersAndAdjustStack(registers_used, 8);

MOV(64, R(R15), ImmPtr(&g_dsp));
MOV(64, R(R15), ImmPtr(&m_dsp_core.DSPState()));

const u8* dispatcherLoop = GetCodePtr();

@@ -28,7 +28,7 @@ namespace JIT::x64
class DSPEmitter final : public JIT::DSPEmitter, public Gen::X64CodeBlock
{
public:
DSPEmitter();
explicit DSPEmitter(DSPCore& dsp);
~DSPEmitter() override;

u16 RunCycles(u16 cycles) override;
@@ -197,6 +197,9 @@ class DSPEmitter final : public JIT::DSPEmitter, public Gen::X64CodeBlock
// within the class itself to allow access to member variables.
static void CompileCurrent(DSPEmitter& emitter);

static u16 ReadIFXRegisterHelper(DSPEmitter& emitter, u16 address);
static void WriteIFXRegisterHelper(DSPEmitter& emitter, u16 address, u16 value);

void EmitInstruction(UDSPInstruction inst);
void ClearIRAMandDSPJITCodespaceReset();

@@ -321,6 +324,8 @@ class DSPEmitter final : public JIT::DSPEmitter, public Gen::X64CodeBlock
const u8* m_enter_dispatcher;
const u8* m_return_dispatcher;
const u8* m_stub_entry_point;

DSPCore& m_dsp_core;
};

} // namespace JIT::x64
@@ -7,7 +7,6 @@
#include "Common/CommonTypes.h"

#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

using namespace Gen;
@@ -65,9 +64,9 @@ void DSPEmitter::andcf(const UDSPInstruction opc)
{
if (FlagsNeeded())
{
u8 reg = (opc >> 8) & 0x1;
const u8 reg = (opc >> 8) & 0x1;
// u16 imm = dsp_fetch_code();
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// u16 val = dsp_get_acc_m(reg);
get_acc_m(reg);
// Update_SR_LZ(((val & imm) == imm) ? true : false);
@@ -100,9 +99,9 @@ void DSPEmitter::andf(const UDSPInstruction opc)
{
if (FlagsNeeded())
{
u8 reg = (opc >> 8) & 0x1;
const u8 reg = (opc >> 8) & 0x1;
// u16 imm = dsp_fetch_code();
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// u16 val = dsp_get_acc_m(reg);
get_acc_m(reg);
// Update_SR_LZ(((val & imm) == 0) ? true : false);
@@ -226,14 +225,14 @@ void DSPEmitter::cmpi(const UDSPInstruction opc)
{
if (FlagsNeeded())
{
u8 reg = (opc >> 8) & 0x1;
X64Reg tmp1 = m_gpr.GetFreeXReg();
const u8 reg = (opc >> 8) & 0x1;
const X64Reg tmp1 = m_gpr.GetFreeXReg();
// s64 val = dsp_get_long_acc(reg);
get_long_acc(reg, tmp1);
MOV(64, R(RAX), R(tmp1));
// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in
// the 40-bit accumulator.
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
MOV(64, R(RDX), Imm64((s64)(s16)imm << 16));
// s64 res = dsp_convert_long_acc(val - imm);
SUB(64, R(RAX), R(RDX));
@@ -451,9 +450,9 @@ void DSPEmitter::notc(const UDSPInstruction opc)
// flags out: --xx xx00
void DSPEmitter::xori(const UDSPInstruction opc)
{
u8 reg = (opc >> 8) & 0x1;
const u8 reg = (opc >> 8) & 0x1;
// u16 imm = dsp_fetch_code();
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// g_dsp.r.acm[reg] ^= imm;
get_acc_m(reg, RAX);
XOR(16, R(RAX), Imm16(imm));
@@ -474,9 +473,9 @@ void DSPEmitter::xori(const UDSPInstruction opc)
// flags out: --xx xx00
void DSPEmitter::andi(const UDSPInstruction opc)
{
u8 reg = (opc >> 8) & 0x1;
const u8 reg = (opc >> 8) & 0x1;
// u16 imm = dsp_fetch_code();
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// g_dsp.r.acm[reg] &= imm;
get_acc_m(reg, RAX);
AND(16, R(RAX), Imm16(imm));
@@ -497,9 +496,9 @@ void DSPEmitter::andi(const UDSPInstruction opc)
// flags out: --xx xx00
void DSPEmitter::ori(const UDSPInstruction opc)
{
u8 reg = (opc >> 8) & 0x1;
const u8 reg = (opc >> 8) & 0x1;
// u16 imm = dsp_fetch_code();
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// g_dsp.r.acm[reg] |= imm;
get_acc_m(reg, RAX);
OR(16, R(RAX), Imm16(imm));
@@ -699,7 +698,7 @@ void DSPEmitter::addi(const UDSPInstruction opc)
get_long_acc(areg, tmp1);
MOV(64, R(RAX), R(tmp1));
// s64 imm = (s16)dsp_fetch_code();
s16 imm = dsp_imem_read(m_compile_pc + 1);
const s16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
// imm <<= 16;
MOV(64, R(RDX), Imm32(imm << 16));
// s64 res = acc + imm;
@@ -6,7 +6,6 @@

#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

@@ -126,7 +125,7 @@ void DSPEmitter::WriteBlockLink(u16 dest)

void DSPEmitter::r_jcc(const UDSPInstruction opc)
{
u16 dest = dsp_imem_read(m_compile_pc + 1);
const u16 dest = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
const DSPOPCTemplate* opcode = GetOpTemplate(opc);

// If the block is unconditional, attempt to link block
@@ -172,7 +171,7 @@ void DSPEmitter::r_call(const UDSPInstruction opc)
{
MOV(16, R(DX), Imm16(m_compile_pc + 2));
dsp_reg_store_stack(StackRegister::Call);
u16 dest = dsp_imem_read(m_compile_pc + 1);
const u16 dest = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
const DSPOPCTemplate* opcode = GetOpTemplate(opc);

// If the block is unconditional, attempt to link block
@@ -228,8 +227,9 @@ void DSPEmitter::r_ifcc(const UDSPInstruction opc)
// NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit
void DSPEmitter::ifcc(const UDSPInstruction opc)
{
const auto& state = m_dsp_core.DSPState();
const u16 address = m_compile_pc + 1;
const DSPOPCTemplate* const op_template = GetOpTemplate(dsp_imem_read(address));
const DSPOPCTemplate* const op_template = GetOpTemplate(state.ReadIMEM(address));

MOV(16, M_SDSP_pc(), Imm16(address + op_template->size));
ReJitConditional(opc, &DSPEmitter::r_ifcc);
@@ -347,7 +347,8 @@ void DSPEmitter::loop(const UDSPInstruction opc)

SetJumpTarget(cnt);
// dsp_skip_inst();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
const auto& state = m_dsp_core.DSPState();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
WriteBranchExit();
m_gpr.FlushRegs(c, false);
SetJumpTarget(exit);
@@ -380,7 +381,8 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
else
{
// dsp_skip_inst();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
const auto& state = m_dsp_core.DSPState();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
WriteBranchExit();
}
}
@@ -396,11 +398,11 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
// Up to 4 nested loops are allowed.
void DSPEmitter::bloop(const UDSPInstruction opc)
{
u16 reg = opc & 0x1f;
const u16 reg = opc & 0x1f;
// u16 cnt = g_dsp.r[reg];
// todo: check if we can use normal variant here
dsp_op_read_reg_dont_saturate(reg, RDX, RegisterExtension::Zero);
u16 loop_pc = dsp_imem_read(m_compile_pc + 1);
const u16 loop_pc = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);

TEST(16, R(EDX), R(EDX));
DSPJitRegCache c(m_gpr);
@@ -417,7 +419,8 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
SetJumpTarget(cnt);
// g_dsp.pc = loop_pc;
// dsp_skip_inst();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
const auto& state = m_dsp_core.DSPState();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
WriteBranchExit();
m_gpr.FlushRegs(c, false);
SetJumpTarget(exit);
@@ -434,11 +437,12 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
// nested loops are allowed.
void DSPEmitter::bloopi(const UDSPInstruction opc)
{
u16 cnt = opc & 0xff;
const auto& state = m_dsp_core.DSPState();
const u16 cnt = opc & 0xff;
// u16 loop_pc = dsp_fetch_code();
u16 loop_pc = dsp_imem_read(m_compile_pc + 1);
const u16 loop_pc = state.ReadIMEM(m_compile_pc + 1);

if (cnt)
if (cnt != 0)
{
MOV(16, R(RDX), Imm16(m_compile_pc + 2));
dsp_reg_store_stack(StackRegister::Call);
@@ -453,7 +457,7 @@ void DSPEmitter::bloopi(const UDSPInstruction opc)
{
// g_dsp.pc = loop_pc;
// dsp_skip_inst();
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
WriteBranchExit();
}
}
@@ -7,7 +7,6 @@
#include "Common/CommonTypes.h"

#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

using namespace Gen;
@@ -65,8 +64,8 @@ void DSPEmitter::lrs(const UDSPInstruction opc)
// Move value from data memory pointed by address M to register $D.
void DSPEmitter::lr(const UDSPInstruction opc)
{
int reg = opc & 0x1F;
u16 address = dsp_imem_read(m_compile_pc + 1);
const int reg = opc & 0x1F;
const u16 address = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
dmem_read_imm(address);
dsp_op_write_reg(reg, EAX);
dsp_conditional_extend_accum(reg);
@@ -78,10 +77,10 @@ void DSPEmitter::lr(const UDSPInstruction opc)
// Store value from register $S to a memory pointed by address M.
void DSPEmitter::sr(const UDSPInstruction opc)
{
u8 reg = opc & 0x1F;
u16 address = dsp_imem_read(m_compile_pc + 1);
const u8 reg = opc & 0x1F;
const u16 address = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);

X64Reg tmp1 = m_gpr.GetFreeXReg();
const X64Reg tmp1 = m_gpr.GetFreeXReg();

dsp_op_read_reg(reg, tmp1);
dmem_write_imm(address, tmp1);
@@ -96,10 +95,10 @@ void DSPEmitter::sr(const UDSPInstruction opc)
// M (M is 8-bit value sign extended).
void DSPEmitter::si(const UDSPInstruction opc)
{
u16 address = (s8)opc;
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u16 address = static_cast<s8>(opc);
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);

X64Reg tmp1 = m_gpr.GetFreeXReg();
const X64Reg tmp1 = m_gpr.GetFreeXReg();

MOV(32, R(tmp1), Imm32((u32)imm));
dmem_write_imm(address, tmp1);
@@ -5,7 +5,6 @@
#include "Common/CommonTypes.h"

#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

using namespace Gen;
@@ -36,8 +35,8 @@ void DSPEmitter::mrr(const UDSPInstruction opc)
// S16 mode.
void DSPEmitter::lri(const UDSPInstruction opc)
{
u8 reg = opc & 0x1F;
u16 imm = dsp_imem_read(m_compile_pc + 1);
const u8 reg = opc & 0x1F;
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
dsp_op_write_reg_imm(reg, imm);
dsp_conditional_extend_accum_imm(reg, imm);
}
@@ -11,7 +11,6 @@
#include "Common/Logging/Log.h"

#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

using namespace Gen;
@@ -6,13 +6,22 @@

#include "Common/Logging/Log.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/Jit/x64/DSPEmitter.h"

using namespace Gen;

namespace DSP::JIT::x64
{
u16 DSPEmitter::ReadIFXRegisterHelper(DSPEmitter& emitter, u16 address)
{
return emitter.m_dsp_core.DSPState().ReadIFX(address);
}

void DSPEmitter::WriteIFXRegisterHelper(DSPEmitter& emitter, u16 address, u16 value)
{
emitter.m_dsp_core.DSPState().WriteIFX(address, value);
}

// clobbers:
// EAX = (s8)g_dsp.reg_stack_ptrs[reg_index]
// expects:
@@ -32,7 +41,7 @@ void DSPEmitter::dsp_reg_stack_push(StackRegister stack_reg)
// g_dsp.reg_stack[reg_index][g_dsp.reg_stack_ptrs[reg_index]] = g_dsp.r[DSP_REG_ST0 + reg_index];
MOV(16, R(tmp1), M_SDSP_r_st(reg_index));
MOVZX(64, 8, RAX, R(AL));
MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stacks[reg_index]));
MOV(64, R(tmp2), ImmPtr(m_dsp_core.DSPState().reg_stacks[reg_index]));
MOV(16, MComplex(tmp2, EAX, SCALE_2, 0), R(tmp1));
m_gpr.PutXReg(tmp1);
m_gpr.PutXReg(tmp2);
@@ -50,7 +59,7 @@ void DSPEmitter::dsp_reg_stack_pop(StackRegister stack_reg)
X64Reg tmp1 = m_gpr.GetFreeXReg();
X64Reg tmp2 = m_gpr.GetFreeXReg();
MOVZX(64, 8, RAX, R(AL));
MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stacks[reg_index]));
MOV(64, R(tmp2), ImmPtr(m_dsp_core.DSPState().reg_stacks[reg_index]));
MOV(16, R(tmp1), MComplex(tmp2, EAX, SCALE_2, 0));
MOV(16, M_SDSP_r_st(reg_index), R(tmp1));
m_gpr.PutXReg(tmp1);
@@ -520,7 +529,7 @@ void DSPEmitter::dmem_write(X64Reg value)

// g_dsp.dram[addr & DSP_DRAM_MASK] = val;
AND(16, R(EAX), Imm16(DSP_DRAM_MASK));
MOV(64, R(ECX), ImmPtr(g_dsp.dram));
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().dram));
MOV(16, MComplex(ECX, EAX, SCALE_2, 0), R(value));

FixupBranch end = J(true);
@@ -530,7 +539,7 @@ void DSPEmitter::dmem_write(X64Reg value)
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
MOVZX(32, 16, abisafereg, R(abisafereg));
m_gpr.PushRegs();
ABI_CallFunctionRR(gdsp_ifx_write, EAX, abisafereg);
ABI_CallFunctionPRR(WriteIFXRegisterHelper, this, EAX, abisafereg);
m_gpr.PopRegs();
m_gpr.FlushRegs(c);
SetJumpTarget(end);
@@ -541,7 +550,7 @@ void DSPEmitter::dmem_write_imm(u16 address, X64Reg value)
switch (address >> 12)
{
case 0x0: // 0xxx DRAM
MOV(64, R(RDX), ImmPtr(g_dsp.dram));
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().dram));
MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK) * 2), R(value));
break;

@@ -550,12 +559,13 @@ void DSPEmitter::dmem_write_imm(u16 address, X64Reg value)
MOV(16, R(EAX), Imm16(address));
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
m_gpr.PushRegs();
ABI_CallFunctionRR(gdsp_ifx_write, EAX, abisafereg);
ABI_CallFunctionPRR(WriteIFXRegisterHelper, this, EAX, abisafereg);
m_gpr.PopRegs();
break;
}
default: // Unmapped/non-existing memory
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory", g_dsp.pc, address);
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory",
m_dsp_core.DSPState().pc, address);
break;
}
}
@@ -570,15 +580,15 @@ void DSPEmitter::imem_read(X64Reg address)
FixupBranch irom = J_CC(CC_A);
// return g_dsp.iram[addr & DSP_IRAM_MASK];
AND(16, R(address), Imm16(DSP_IRAM_MASK));
MOV(64, R(ECX), ImmPtr(g_dsp.iram));
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().iram));
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));

FixupBranch end = J();
SetJumpTarget(irom);
// else if (addr == 0x8)
// return g_dsp.irom[addr & DSP_IROM_MASK];
AND(16, R(address), Imm16(DSP_IROM_MASK));
MOV(64, R(ECX), ImmPtr(g_dsp.irom));
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().irom));
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));

SetJumpTarget(end);
@@ -594,7 +604,7 @@ void DSPEmitter::dmem_read(X64Reg address)
FixupBranch dram = J_CC(CC_A);
// return g_dsp.dram[addr & DSP_DRAM_MASK];
AND(32, R(address), Imm32(DSP_DRAM_MASK));
MOV(64, R(ECX), ImmPtr(g_dsp.dram));
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().dram));
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));

FixupBranch end = J(true);
@@ -604,7 +614,7 @@ void DSPEmitter::dmem_read(X64Reg address)
FixupBranch ifx = J_CC(CC_A);
// return g_dsp.coef[addr & DSP_COEF_MASK];
AND(32, R(address), Imm32(DSP_COEF_MASK));
MOV(64, R(ECX), ImmPtr(g_dsp.coef));
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().coef));
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));

FixupBranch end2 = J(true);
@@ -614,7 +624,7 @@ void DSPEmitter::dmem_read(X64Reg address)
DSPJitRegCache c(m_gpr);
X64Reg abisafereg = m_gpr.MakeABICallSafe(address);
m_gpr.PushRegs();
ABI_CallFunctionR(gdsp_ifx_read, abisafereg);
ABI_CallFunctionPR(ReadIFXRegisterHelper, this, abisafereg);
m_gpr.PopRegs();
m_gpr.FlushRegs(c);
SetJumpTarget(end);
@@ -626,24 +636,25 @@ void DSPEmitter::dmem_read_imm(u16 address)
switch (address >> 12)
{
case 0x0: // 0xxx DRAM
MOV(64, R(RDX), ImmPtr(g_dsp.dram));
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().dram));
MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK) * 2));
break;

case 0x1: // 1xxx COEF
MOV(64, R(RDX), ImmPtr(g_dsp.coef));
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().coef));
MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK) * 2));
break;

case 0xf: // Fxxx HW regs
{
m_gpr.PushRegs();
ABI_CallFunctionC16(gdsp_ifx_read, address);
ABI_CallFunctionPC(ReadIFXRegisterHelper, this, address);
m_gpr.PopRegs();
break;
}
default: // Unmapped/non-existing memory
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory", g_dsp.pc, address);
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory",
m_dsp_core.DSPState().pc, address);
}
}

This file was deleted.

This file was deleted.

@@ -68,31 +68,33 @@ void InterruptRequest()
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}

void CodeLoaded(u32 addr, size_t size)
void CodeLoaded(DSPCore& dsp, u32 addr, size_t size)
{
CodeLoaded(Memory::GetPointer(addr), size);
CodeLoaded(dsp, Memory::GetPointer(addr), size);
}

void CodeLoaded(const u8* ptr, size_t size)
void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
{
g_dsp.iram_crc = Common::HashEctor(ptr, size);
auto& state = dsp.DSPState();
const u32 iram_crc = Common::HashEctor(ptr, size);
state.iram_crc = iram_crc;

if (SConfig::GetInstance().m_DumpUCode)
{
DSP::DumpDSPCode(ptr, size, g_dsp.iram_crc);
DSP::DumpDSPCode(ptr, size, iram_crc);
}

NOTICE_LOG_FMT(DSPLLE, "g_dsp.iram_crc: {:08x}", g_dsp.iram_crc);
NOTICE_LOG_FMT(DSPLLE, "g_dsp.iram_crc: {:08x}", iram_crc);

Symbols::Clear();
Symbols::AutoDisassembly(0x0, 0x1000);
Symbols::AutoDisassembly(0x8000, 0x9000);
Symbols::AutoDisassembly(state, 0x0, 0x1000);
Symbols::AutoDisassembly(state, 0x8000, 0x9000);

UpdateDebugger();

if (g_dsp_jit)
g_dsp_jit->ClearIRAM();
dsp.ClearIRAM();

Analyzer::Analyze();
Analyzer::Analyze(state);
}

void UpdateDebugger()
@@ -21,7 +21,6 @@
#include "Core/DSP/DSPAccelerator.h"
#include "Core/DSP/DSPCaptureLogger.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
@@ -32,15 +31,11 @@

namespace DSP::LLE
{
static Common::Event s_dsp_event;
static Common::Event s_ppc_event;
static bool s_request_disable_thread;

DSPLLE::DSPLLE() = default;

DSPLLE::~DSPLLE()
{
DSPCore_Shutdown();
m_dsp_core.Shutdown();
DSP_StopSoundStream();
}

@@ -55,39 +50,8 @@ void DSPLLE::DoState(PointerWrap& p)
p.SetMode(PointerWrap::MODE_VERIFY);
return;
}
p.Do(g_dsp.r);
p.Do(g_dsp.pc);
#if PROFILE
p.Do(g_dsp.err_pc);
#endif
p.Do(g_dsp.cr);
p.Do(g_dsp.reg_stack_ptrs);
p.Do(g_dsp.exceptions);
p.Do(g_dsp.external_interrupt_waiting);

for (auto& stack : g_dsp.reg_stacks)
{
p.Do(stack);
}

p.Do(g_dsp.step_counter);
p.DoArray(g_dsp.ifx_regs);
g_dsp.accelerator->DoState(p);
p.Do(g_dsp.mbox[0]);
p.Do(g_dsp.mbox[1]);
Common::UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
p.DoArray(g_dsp.iram, DSP_IRAM_SIZE);
Common::WriteProtectMemory(g_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(reinterpret_cast<const u8*>(g_dsp.iram), DSP_IRAM_BYTE_SIZE);
p.DoArray(g_dsp.dram, DSP_DRAM_SIZE);
p.Do(g_init_hax);
m_dsp_core.DoState(p);
p.Do(m_cycle_count);

if (g_dsp_jit)
g_dsp_jit->DoState(p);
}

// Regular thread
@@ -103,21 +67,21 @@ void DSPLLE::DSPThread(DSPLLE* dsp_lle)
std::unique_lock dsp_thread_lock(dsp_lle->m_dsp_thread_mutex, std::try_to_lock);
if (dsp_thread_lock)
{
if (g_dsp_jit)
if (dsp_lle->m_dsp_core.IsJITCreated())
{
DSPCore_RunCycles(cycles);
dsp_lle->m_dsp_core.RunCycles(cycles);
}
else
{
DSP::Interpreter::RunCyclesThread(cycles);
dsp_lle->m_dsp_core.GetInterpreter().RunCyclesThread(cycles);
}
dsp_lle->m_cycle_count.store(0);
continue;
}
}

s_ppc_event.Set();
s_dsp_event.Wait();
dsp_lle->m_ppc_event.Set();
dsp_lle->m_dsp_event.Wait();
}
}

@@ -173,22 +137,22 @@ static bool FillDSPInitOptions(DSPInitOptions* opts)

bool DSPLLE::Initialize(bool wii, bool dsp_thread)
{
s_request_disable_thread = false;
m_request_disable_thread = false;

DSPInitOptions opts;
if (!FillDSPInitOptions(&opts))
return false;
if (!DSPCore_Init(opts))
if (!m_dsp_core.Initialize(opts))
return false;

// needs to be after DSPCore_Init for the dspjit ptr
if (Core::WantsDeterminism() || !g_dsp_jit)
if (Core::WantsDeterminism() || !m_dsp_core.IsJITCreated())
dsp_thread = false;

m_wii = wii;
m_is_dsp_on_thread = dsp_thread;

DSPCore_Reset();
m_dsp_core.Reset();

InitInstructionTable();

@@ -204,77 +168,70 @@ bool DSPLLE::Initialize(bool wii, bool dsp_thread)

void DSPLLE::DSP_StopSoundStream()
{
if (m_is_dsp_on_thread)
{
m_is_running.Clear();
s_ppc_event.Set();
s_dsp_event.Set();
m_dsp_thread.join();
}
if (!m_is_dsp_on_thread)
return;

m_is_running.Clear();
m_ppc_event.Set();
m_dsp_event.Set();
m_dsp_thread.join();
}

void DSPLLE::Shutdown()
{
DSPCore_Shutdown();
m_dsp_core.Shutdown();
}

u16 DSPLLE::DSP_WriteControlRegister(u16 value)
{
DSP::Interpreter::WriteCR(value);
m_dsp_core.GetInterpreter().WriteCR(value);

if (value & 2)
if ((value & 2) != 0)
{
if (!m_is_dsp_on_thread)
{
DSPCore_CheckExternalInterrupt();
DSPCore_CheckExceptions();
}
else
if (m_is_dsp_on_thread)
{
// External interrupt pending: this is the zelda ucode.
// Disable the DSP thread because there is no performance gain.
s_request_disable_thread = true;
m_request_disable_thread = true;

DSPCore_SetExternalInterrupt(true);
m_dsp_core.SetExternalInterrupt(true);
}
else
{
m_dsp_core.CheckExternalInterrupt();
m_dsp_core.CheckExceptions();
}
}

return DSP::Interpreter::ReadCR();
return DSP_ReadControlRegister();
}

u16 DSPLLE::DSP_ReadControlRegister()
{
return DSP::Interpreter::ReadCR();
return m_dsp_core.GetInterpreter().ReadCR();
}

u16 DSPLLE::DSP_ReadMailBoxHigh(bool cpu_mailbox)
{
return gdsp_mbox_read_h(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
return m_dsp_core.ReadMailboxHigh(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
}

u16 DSPLLE::DSP_ReadMailBoxLow(bool cpu_mailbox)
{
return gdsp_mbox_read_l(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
return m_dsp_core.ReadMailboxLow(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
}

void DSPLLE::DSP_WriteMailBoxHigh(bool cpu_mailbox, u16 value)
{
if (cpu_mailbox)
{
if (gdsp_mbox_peek(MAILBOX_CPU) & 0x80000000)
if ((m_dsp_core.PeekMailbox(MAILBOX_CPU) & 0x80000000) != 0)
{
// the DSP didn't read the previous value
WARN_LOG_FMT(DSPLLE, "Mailbox isn't empty ... strange");
}

#if PROFILE
if (value == 0xBABE)
{
ProfilerStart();
}
#endif

gdsp_mbox_write_h(MAILBOX_CPU, value);
m_dsp_core.WriteMailboxHigh(MAILBOX_CPU, value);
}
else
{
@@ -286,7 +243,7 @@ void DSPLLE::DSP_WriteMailBoxLow(bool cpu_mailbox, u16 value)
{
if (cpu_mailbox)
{
gdsp_mbox_write_l(MAILBOX_CPU, value);
m_dsp_core.WriteMailboxLow(MAILBOX_CPU, value);
}
else
{
@@ -296,18 +253,18 @@ void DSPLLE::DSP_WriteMailBoxLow(bool cpu_mailbox, u16 value)

void DSPLLE::DSP_Update(int cycles)
{
int dsp_cycles = cycles / 6;
const int dsp_cycles = cycles / 6;

if (dsp_cycles <= 0)
return;

if (m_is_dsp_on_thread)
{
if (s_request_disable_thread || Core::WantsDeterminism())
if (m_request_disable_thread || Core::WantsDeterminism())
{
DSP_StopSoundStream();
m_is_dsp_on_thread = false;
s_request_disable_thread = false;
m_request_disable_thread = false;
SConfig::GetInstance().bDSPThread = false;
}
}
@@ -316,14 +273,14 @@ void DSPLLE::DSP_Update(int cycles)
if (!m_is_dsp_on_thread)
{
// ~1/6th as many cycles as the period PPC-side.
DSPCore_RunCycles(dsp_cycles);
m_dsp_core.RunCycles(dsp_cycles);
}
else
{
// Wait for DSP thread to complete its cycle. Note: this logic should be thought through.
s_ppc_event.Wait();
m_ppc_event.Wait();
m_cycle_count.fetch_add(dsp_cycles);
s_dsp_event.Set();
m_dsp_event.Set();
}
}

@@ -345,8 +302,8 @@ void DSPLLE::PauseAndLock(bool do_lock, bool unpause_on_unlock)
if (m_is_dsp_on_thread)
{
// Signal the DSP thread so it can perform any outstanding work now (if any)
s_ppc_event.Wait();
s_dsp_event.Set();
m_ppc_event.Wait();
m_dsp_event.Set();
}
}
}
@@ -10,6 +10,7 @@

#include "Common/CommonTypes.h"
#include "Common/Flag.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSPEmulator.h"

class PointerWrap;
@@ -41,10 +42,15 @@ class DSPLLE : public DSPEmulator
private:
static void DSPThread(DSPLLE* dsp_lle);

DSPCore m_dsp_core;
std::thread m_dsp_thread;
std::mutex m_dsp_thread_mutex;
bool m_is_dsp_on_thread = false;
Common::Flag m_is_running;
std::atomic<u32> m_cycle_count{};

Common::Event m_dsp_event;
Common::Event m_ppc_event;
bool m_request_disable_thread = false;
};
} // namespace DSP::LLE
@@ -69,15 +69,15 @@ Common::Symbol* DSPSymbolDB::GetSymbolFromAddr(u32 addr)
return nullptr;
}

void AutoDisassembly(u16 start_addr, u16 end_addr)
void AutoDisassembly(const SDSP& dsp, u16 start_addr, u16 end_addr)
{
AssemblerSettings settings;
settings.show_pc = true;
settings.show_hex = true;
DSPDisassembler disasm(settings);

u16 addr = start_addr;
const u16* ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram;
const u16* ptr = (start_addr >> 15) != 0 ? dsp.irom : dsp.iram;
while (addr < end_addr)
{
line_to_addr[line_counter] = addr;
@@ -9,6 +9,11 @@
#include "Common/CommonTypes.h"
#include "Common/SymbolDB.h"

namespace DSP
{
struct SDSP;
}

namespace DSP::Symbols
{
class DSPSymbolDB : public Common::SymbolDB
@@ -21,7 +26,7 @@ class DSPSymbolDB : public Common::SymbolDB

extern DSPSymbolDB g_dsp_symbol_db;

void AutoDisassembly(u16 start_addr, u16 end_addr);
void AutoDisassembly(const SDSP& dsp, u16 start_addr, u16 end_addr);

void Clear();

@@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;

// Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 125; // Last changed in PR 8867
constexpr u32 STATE_VERSION = 126; // Last changed in PR 9348

// Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list,
@@ -39,10 +39,10 @@ bool DSP::Host::IsWiiHost()
{
return false;
}
void DSP::Host::CodeLoaded(u32 addr, size_t size)
void DSP::Host::CodeLoaded(DSPCore& dsp, u32 addr, size_t size)
{
}
void DSP::Host::CodeLoaded(const u8* ptr, size_t size)
void DSP::Host::CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
{
}
void DSP::Host::InterruptRequest()