DSP: Eliminate most global state

An unfortunately large single commit that deglobalizes the DSP code.
(which I'm very sorry about).

This would have otherwise been extremely difficult to separate due to
extensive use of the globals in very coupling ways that would result in
more scaffolding to work around than is worth it.

Aside from the video code, I believe only the DSP code is the hairiest
to deal with in terms of globals, so I guess it's best to get this dealt
with right off the bat.

A summary of what this commit does:
  - Turns the DSPInterpreter into its own class
    This is the most involved portion of this change.
    The bulk of the changes are turning non-member functions into member
    functions that would be situated into the Interpreter class.

  - Eliminates all usages to globals within DSPCore.
    This generally involves turning a lot of non-member functions into
    member functions that are either situated within SDSP or DSPCore.

  - Discards DSPDebugInterface (it wasn't hooked up to anything,
    and for the sake of eliminating global state, I'd rather get rid of
    it than think up ways for this class to be integrated with
    everything else.

  - Readjusts the DSP JIT to handle calling out to member functions.
    In most cases, this just means wrapping respective member function
    calles into thunk functions.

Surprisingly, this doesn't even make use of the introduced System class.
It was possible all along to do this without it. We can house everything
within the DSPLLE class, which is quite nice =)
This commit is contained in:
Lioncash committed 2020-12-27 06:38:02 -05:00
1 parent 2917af03ec
commit 7d1bd565a6
50 files changed
+3037 -3164

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -5,10 +5,6 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPStacks.h"
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSP::Interpreter
@@ -20,14 +16,16 @@ namespace DSP::Interpreter
// Call function if condition cc has been met. Push program counter of
// instruction following "call" to $st0. Set program counter to address
// represented by value that follows this "call" instruction.
void call(const UDSPInstruction opc)
void Interpreter::call(const UDSPInstruction opc)
{
auto& state = m_dsp_core.DSPState();
// must be outside the if.
u16 dest = dsp_fetch_code();
const u16 dest = state.FetchInstruction();
if (CheckCondition(opc & 0xf))
{
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
g_dsp.pc = dest;
state.StoreStack(StackRegister::Call, state.pc);
state.pc = dest;
}
}
@@ -37,28 +35,29 @@ void call(const UDSPInstruction opc)
// Call function if condition cc has been met. Push program counter of
// instruction following "call" to call stack $st0. Set program counter to
// register $R.
void callr(const UDSPInstruction opc)
void Interpreter::callr(const UDSPInstruction opc)
{
if (CheckCondition(opc & 0xf))
{
u8 reg = (opc >> 5) & 0x7;
u16 addr = dsp_op_read_reg(reg);
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
g_dsp.pc = addr;
}
if (!CheckCondition(opc & 0xf))
return;
auto& state = m_dsp_core.DSPState();
const u8 reg = (opc >> 5) & 0x7;
const u16 addr = OpReadRegister(reg);
state.StoreStack(StackRegister::Call, state.pc);
state.pc = addr;
}
// Generic if implementation
// IFcc
// 0000 0010 0111 cccc
// Execute following opcode if the condition has been met.
void ifcc(const UDSPInstruction opc)
void Interpreter::ifcc(const UDSPInstruction opc)
{
if (!CheckCondition(opc & 0xf))
{
// skip the next opcode - we have to lookup its size.
dsp_skip_inst();
}
if (CheckCondition(opc & 0xf))
return;
// skip the next opcode - we have to lookup its size.
m_dsp_core.DSPState().SkipInstruction();
}
// Generic jmp implementation
@@ -67,12 +66,13 @@ void ifcc(const UDSPInstruction opc)
// aaaa aaaa aaaa aaaa
// Jump to addressA if condition cc has been met. Set program counter to
// address represented by value that follows this "jmp" instruction.
void jcc(const UDSPInstruction opc)
void Interpreter::jcc(const UDSPInstruction opc)
{
u16 dest = dsp_fetch_code();
auto& state = m_dsp_core.DSPState();
const u16 dest = state.FetchInstruction();
if (CheckCondition(opc & 0xf))
{
g_dsp.pc = dest;
state.pc = dest;
}
}
@@ -80,13 +80,14 @@ void jcc(const UDSPInstruction opc)
// JMPcc $R
// 0001 0111 rrr0 cccc
// Jump to address; set program counter to a value from register $R.
void jmprcc(const UDSPInstruction opc)
void Interpreter::jmprcc(const UDSPInstruction opc)
{
if (CheckCondition(opc & 0xf))
{
u8 reg = (opc >> 5) & 0x7;
g_dsp.pc = dsp_op_read_reg(reg);
}
if (!CheckCondition(opc & 0xf))
return;
auto& state = m_dsp_core.DSPState();
const u8 reg = (opc >> 5) & 0x7;
state.pc = OpReadRegister(reg);
}
// Generic ret implementation
@@ -94,12 +95,13 @@ void jmprcc(const UDSPInstruction opc)
// 0000 0010 1101 cccc
// Return from subroutine if condition cc has been met. Pops stored PC
// from call stack $st0 and sets $pc to this location.
void ret(const UDSPInstruction opc)
void Interpreter::ret(const UDSPInstruction opc)
{
if (CheckCondition(opc & 0xf))
{
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
}
if (!CheckCondition(opc & 0xf))
return;
auto& state = m_dsp_core.DSPState();
state.pc = state.PopStack(StackRegister::Call);
}
// RTI
@@ -107,19 +109,21 @@ void ret(const UDSPInstruction opc)
// Return from exception. Pops stored status register $sr from data stack
// $st1 and program counter PC from call stack $st0 and sets $pc to this
// location.
void rti(const UDSPInstruction opc)
void Interpreter::rti(const UDSPInstruction)
{
g_dsp.r.sr = dsp_reg_load_stack(StackRegister::Data);
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
auto& state = m_dsp_core.DSPState();
state.r.sr = state.PopStack(StackRegister::Data);
state.pc = state.PopStack(StackRegister::Call);
}
// HALT
// 0000 0000 0020 0001
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
void halt(const UDSPInstruction opc)
void Interpreter::halt(const UDSPInstruction)
{
g_dsp.cr |= 0x4;
g_dsp.pc--;
auto& state = m_dsp_core.DSPState();
state.cr |= 0x4;
state.pc--;
}
// LOOP handling: Loop stack is used to control execution of repeated blocks of
@@ -128,29 +132,31 @@ void halt(const UDSPInstruction opc)
// then PC is modified with value from call stack $st0. Otherwise values from
// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution
// continues at next opcode.
void HandleLoop()
void Interpreter::HandleLoop()
{
auto& state = m_dsp_core.DSPState();
// Handle looping hardware.
const u16 rCallAddress = g_dsp.r.st[0];
const u16 rLoopAddress = g_dsp.r.st[2];
u16& rLoopCounter = g_dsp.r.st[3];
const u16 rCallAddress = state.r.st[0];
const u16 rLoopAddress = state.r.st[2];
u16& rLoopCounter = state.r.st[3];
if (rLoopAddress > 0 && rLoopCounter > 0)
{
// FIXME: why -1? because we just read past it.
if (g_dsp.pc - 1 == rLoopAddress)
if (state.pc - 1 == rLoopAddress)
{
rLoopCounter--;
if (rLoopCounter > 0)
{
g_dsp.pc = rCallAddress;
state.pc = rCallAddress;
}
else
{
// end of loop
dsp_reg_load_stack(StackRegister::Call);
dsp_reg_load_stack(StackRegister::LoopAddress);
dsp_reg_load_stack(StackRegister::LoopCounter);
state.PopStack(StackRegister::Call);
state.PopStack(StackRegister::LoopAddress);
state.PopStack(StackRegister::LoopCounter);
}
}
}
@@ -164,21 +170,22 @@ void HandleLoop()
// then looped instruction will not get executed.
// Actually, this instruction simply prepares the loop stacks for the above.
// The looping hardware takes care of the rest.
void loop(const UDSPInstruction opc)
void Interpreter::loop(const UDSPInstruction opc)
{
u16 reg = opc & 0x1f;
u16 cnt = dsp_op_read_reg(reg);
u16 loop_pc = g_dsp.pc;
auto& state = m_dsp_core.DSPState();
const u16 reg = opc & 0x1f;
const u16 cnt = OpReadRegister(reg);
const u16 loop_pc = state.pc;
if (cnt)
if (cnt != 0)
{
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
state.StoreStack(StackRegister::Call, state.pc);
state.StoreStack(StackRegister::LoopAddress, loop_pc);
state.StoreStack(StackRegister::LoopCounter, cnt);
}
else
{
dsp_skip_inst();
state.SkipInstruction();
}
}
@@ -190,20 +197,21 @@ void loop(const UDSPInstruction opc)
// instruction will not get executed.
// Actually, this instruction simply prepares the loop stacks for the above.
// The looping hardware takes care of the rest.
void loopi(const UDSPInstruction opc)
void Interpreter::loopi(const UDSPInstruction opc)
{
u16 cnt = opc & 0xff;
u16 loop_pc = g_dsp.pc;
auto& state = m_dsp_core.DSPState();
const u16 cnt = opc & 0xff;
const u16 loop_pc = state.pc;
if (cnt)
if (cnt != 0)
{
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
state.StoreStack(StackRegister::Call, state.pc);
state.StoreStack(StackRegister::LoopAddress, loop_pc);
state.StoreStack(StackRegister::LoopCounter, cnt);
}
else
{
dsp_skip_inst();
state.SkipInstruction();
}
}
@@ -216,22 +224,23 @@ void loopi(const UDSPInstruction opc)
// included in loop. Counter is pushed on loop stack $st3, end of block address
// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
// Up to 4 nested loops are allowed.
void bloop(const UDSPInstruction opc)
void Interpreter::bloop(const UDSPInstruction opc)
{
u16 reg = opc & 0x1f;
u16 cnt = dsp_op_read_reg(reg);
u16 loop_pc = dsp_fetch_code();
auto& state = m_dsp_core.DSPState();
const u16 reg = opc & 0x1f;
const u16 cnt = OpReadRegister(reg);
const u16 loop_pc = state.FetchInstruction();
if (cnt)
if (cnt != 0)
{
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
state.StoreStack(StackRegister::Call, state.pc);
state.StoreStack(StackRegister::LoopAddress, loop_pc);
state.StoreStack(StackRegister::LoopCounter, cnt);
}
else
{
g_dsp.pc = loop_pc;
dsp_skip_inst();
state.pc = loop_pc;
state.SkipInstruction();
}
}
@@ -244,21 +253,22 @@ void bloop(const UDSPInstruction opc)
// loop. Counter is pushed on loop stack $st3, end of block address is pushed
// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
// nested loops are allowed.
void bloopi(const UDSPInstruction opc)
void Interpreter::bloopi(const UDSPInstruction opc)
{
u16 cnt = opc & 0xff;
u16 loop_pc = dsp_fetch_code();
auto& state = m_dsp_core.DSPState();
const u16 cnt = opc & 0xff;
const u16 loop_pc = state.FetchInstruction();
if (cnt)
if (cnt != 0)
{
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
state.StoreStack(StackRegister::Call, state.pc);
state.StoreStack(StackRegister::LoopAddress, loop_pc);
state.StoreStack(StackRegister::LoopCounter, cnt);
}
else
{
g_dsp.pc = loop_pc;
dsp_skip_inst();
state.pc = loop_pc;
state.SkipInstruction();
}
}
} // namespace DSP::Interpreter
@@ -1,183 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
//
// Additional copyrights go to Duddie and Tratax (c) 2004
// HELPER FUNCTIONS
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/DSPCore.h"
namespace DSP::Interpreter
{
void Update_SR_Register64(s64 _Value, bool carry, bool overflow)
{
g_dsp.r.sr &= ~SR_CMP_MASK;
// 0x01
if (carry)
{
g_dsp.r.sr |= SR_CARRY;
}
// 0x02 and 0x80
if (overflow)
{
g_dsp.r.sr |= SR_OVERFLOW;
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
}
// 0x04
if (_Value == 0)
{
g_dsp.r.sr |= SR_ARITH_ZERO;
}
// 0x08
if (_Value < 0)
{
g_dsp.r.sr |= SR_SIGN;
}
// 0x10
if (_Value != (s32)_Value)
{
g_dsp.r.sr |= SR_OVER_S32;
}
// 0x20 - Checks if top bits of m are equal
if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000))
{
g_dsp.r.sr |= SR_TOP2BITS;
}
}
void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32)
{
g_dsp.r.sr &= ~SR_CMP_MASK;
// 0x01
if (carry)
{
g_dsp.r.sr |= SR_CARRY;
}
// 0x02 and 0x80
if (overflow)
{
g_dsp.r.sr |= SR_OVERFLOW;
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
}
// 0x04
if (_Value == 0)
{
g_dsp.r.sr |= SR_ARITH_ZERO;
}
// 0x08
if (_Value < 0)
{
g_dsp.r.sr |= SR_SIGN;
}
// 0x10
if (overS32)
{
g_dsp.r.sr |= SR_OVER_S32;
}
// 0x20 - Checks if top bits of m are equal
if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
{
g_dsp.r.sr |= SR_TOP2BITS;
}
}
void Update_SR_LZ(bool value)
{
if (value == true)
g_dsp.r.sr |= SR_LOGIC_ZERO;
else
g_dsp.r.sr &= ~SR_LOGIC_ZERO;
}
static bool IsCarry()
{
return (g_dsp.r.sr & SR_CARRY) != 0;
}
static bool IsOverflow()
{
return (g_dsp.r.sr & SR_OVERFLOW) != 0;
}
static bool IsOverS32()
{
return (g_dsp.r.sr & SR_OVER_S32) != 0;
}
static bool IsLess()
{
return (g_dsp.r.sr & SR_OVERFLOW) != (g_dsp.r.sr & SR_SIGN);
}
static bool IsZero()
{
return (g_dsp.r.sr & SR_ARITH_ZERO) != 0;
}
static bool IsLogicZero()
{
return (g_dsp.r.sr & SR_LOGIC_ZERO) != 0;
}
static bool IsConditionA()
{
return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) &&
!(g_dsp.r.sr & SR_ARITH_ZERO)) != 0;
}
// see DSPCore.h for flags
bool CheckCondition(u8 _Condition)
{
switch (_Condition & 0xf)
{
case 0xf: // Always true.
return true;
case 0x0: // GE - Greater Equal
return !IsLess();
case 0x1: // L - Less
return IsLess();
case 0x2: // G - Greater
return !IsLess() && !IsZero();
case 0x3: // LE - Less Equal
return IsLess() || IsZero();
case 0x4: // NZ - Not Zero
return !IsZero();
case 0x5: // Z - Zero
return IsZero();
case 0x6: // NC - Not carry
return !IsCarry();
case 0x7: // C - Carry
return IsCarry();
case 0x8: // ? - Not over s32
return !IsOverS32();
case 0x9: // ? - Over s32
return IsOverS32();
case 0xa: // ?
return IsConditionA();
case 0xb: // ?
return !IsConditionA();
case 0xc: // LNZ - Logic Not Zero
return !IsLogicZero();
case 0xd: // LZ - Logic Zero
return IsLogicZero();
case 0xe: // 0 - Overflow
return IsOverflow();
default:
return true;
}
}
} // namespace DSP::Interpreter
@@ -6,36 +6,29 @@
#pragma once
// Anything to do with SR and conditions goes here.
#include "Common/CommonTypes.h"
// Anything to do with SR and conditions goes here.
namespace DSP::Interpreter
{
bool CheckCondition(u8 _Condition);
void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false,
bool overS32 = false);
void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false);
void Update_SR_LZ(bool value);
inline bool isCarry(u64 val, u64 result)
constexpr bool isCarry(u64 val, u64 result)
{
return (val > result);
return val > result;
}
inline bool isCarry2(u64 val, u64 result)
constexpr bool isCarry2(u64 val, u64 result)
{
return (val >= result);
return val >= result;
}
inline bool isOverflow(s64 val1, s64 val2, s64 res)
constexpr bool isOverflow(s64 val1, s64 val2, s64 res)
{
return ((val1 ^ res) & (val2 ^ res)) < 0;
}
inline bool isOverS32(s64 acc)
constexpr bool isOverS32(s64 acc)
{
return (acc != (s32)acc) ? true : false;
return acc != static_cast<s32>(acc);
}
} // namespace DSP::Interpreter
+212 -261
View File
@@ -2,15 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
// not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS
// dspjit64 without it)
//#define PRECISE_BACKLOG
#include "Core/DSP/Interpreter/DSPInterpreter.h"
// Extended opcodes do not exist on their own. These opcodes can only be
// attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by
@@ -22,15 +14,7 @@
// registers will wrap in odd ways, dictated by the corresponding wrapping
// register, WR0-3.
namespace DSP
{
static void WriteToBackLog(int i, int idx, u16 value)
{
writeBackLog[i] = value;
writeBackLogIdx[i] = idx;
}
namespace Interpreter::Ext
namespace DSP::Interpreter
{
static bool IsSameMemArea(u16 a, u16 b)
{
@@ -41,46 +25,48 @@ static bool IsSameMemArea(u16 a, u16 b)
// DR $arR
// xxxx xxxx 0000 01rr
// Decrement addressing register $arR.
void dr(const UDSPInstruction opc)
void Interpreter::dr(const UDSPInstruction opc)
{
WriteToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3));
WriteToBackLog(0, opc & 0x3, DecrementAddressRegister(opc & 0x3));
}
// IR $arR
// xxxx xxxx 0000 10rr
// Increment addressing register $arR.
void ir(const UDSPInstruction opc)
void Interpreter::ir(const UDSPInstruction opc)
{
WriteToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3));
WriteToBackLog(0, opc & 0x3, IncrementAddressRegister(opc & 0x3));
}
// NR $arR
// xxxx xxxx 0000 11rr
// Add corresponding indexing register $ixR to addressing register $arR.
void nr(const UDSPInstruction opc)
void Interpreter::nr(const UDSPInstruction opc)
{
u8 reg = opc & 0x3;
const u8 reg = opc & 0x3;
const auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]));
WriteToBackLog(0, reg, IncreaseAddressRegister(reg, static_cast<s16>(state.r.ix[reg])));
}
// MV $axD.D, $acS.S
// xxxx xxxx 0001 ddss
// Move value of $acS.S to the $axD.D.
void mv(const UDSPInstruction opc)
void Interpreter::mv(const UDSPInstruction opc)
{
u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
u8 dreg = ((opc >> 2) & 0x3);
const u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
const u8 dreg = ((opc >> 2) & 0x3);
auto& state = m_dsp_core.DSPState();
switch (sreg)
{
case DSP_REG_ACL0:
case DSP_REG_ACL1:
WriteToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
WriteToBackLog(0, dreg + DSP_REG_AXL0, state.r.ac[sreg - DSP_REG_ACL0].l);
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
WriteToBackLog(0, dreg + DSP_REG_AXL0, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
WriteToBackLog(0, dreg + DSP_REG_AXL0, OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
break;
}
}
@@ -89,69 +75,72 @@ void mv(const UDSPInstruction opc)
// xxxx xxxx 001s s0dd
// Store value of $acS.S in the memory pointed by register $arD.
// Post increment register $arD.
void s(const UDSPInstruction opc)
void Interpreter::s(const UDSPInstruction opc)
{
u8 dreg = opc & 0x3;
u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
const u8 dreg = opc & 0x3;
const u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
auto& state = m_dsp_core.DSPState();
switch (sreg)
{
case DSP_REG_ACL0:
case DSP_REG_ACL1:
dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
state.WriteDMEM(state.r.ar[dreg], state.r.ac[sreg - DSP_REG_ACL0].l);
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
break;
}
WriteToBackLog(0, dreg, dsp_increment_addr_reg(dreg));
WriteToBackLog(0, dreg, IncrementAddressRegister(dreg));
}
// SN @$arD, $acS.S
// xxxx xxxx 001s s1dd
// Store value of register $acS.S in the memory pointed by register $arD.
// Add indexing register $ixD to register $arD.
void sn(const UDSPInstruction opc)
void Interpreter::sn(const UDSPInstruction opc)
{
u8 dreg = opc & 0x3;
u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
const u8 dreg = opc & 0x3;
const u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
auto& state = m_dsp_core.DSPState();
switch (sreg)
{
case DSP_REG_ACL0:
case DSP_REG_ACL1:
dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
state.WriteDMEM(state.r.ar[dreg], state.r.ac[sreg - DSP_REG_ACL0].l);
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
break;
}
WriteToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]));
WriteToBackLog(0, dreg, IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg])));
}
// L $axD.D, @$arS
// xxxx xxxx 01dd d0ss
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
// Post increment register $arS.
void l(const UDSPInstruction opc)
void Interpreter::l(const UDSPInstruction opc)
{
u8 sreg = opc & 0x3;
u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
const u8 sreg = opc & 0x3;
const u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
if (dreg >= DSP_REG_ACM0 && IsSRFlagSet(SR_40_MODE_BIT))
{
u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
const u16 val = state.ReadDMEM(state.r.ar[sreg]);
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) != 0 ? 0xFFFF : 0x0000);
WriteToBackLog(1, dreg, val);
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
WriteToBackLog(3, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(3, sreg, IncrementAddressRegister(sreg));
}
else
{
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(1, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[sreg]));
WriteToBackLog(1, sreg, IncrementAddressRegister(sreg));
}
}
@@ -159,23 +148,24 @@ void l(const UDSPInstruction opc)
// xxxx xxxx 01dd d0ss
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
// Add indexing register $ixS to register $arS.
void ln(const UDSPInstruction opc)
void Interpreter::ln(const UDSPInstruction opc)
{
u8 sreg = opc & 0x3;
u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
const u8 sreg = opc & 0x3;
const u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
if (dreg >= DSP_REG_ACM0 && IsSRFlagSet(SR_40_MODE_BIT))
{
u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
const u16 val = state.ReadDMEM(state.r.ar[sreg]);
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) != 0 ? 0xFFFF : 0x0000);
WriteToBackLog(1, dreg, val);
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
WriteToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(3, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
}
else
{
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[sreg]));
WriteToBackLog(1, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
}
}
@@ -184,16 +174,17 @@ void ln(const UDSPInstruction opc)
// Load register $axD.D with value from memory pointed by register
// $ar0. Store value from register $acS.m to memory location pointed by
// register $ar3. Increment both $ar0 and $ar3.
void ls(const UDSPInstruction opc)
void Interpreter::ls(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
}
// LSN $axD.D, $acS.m
@@ -202,16 +193,18 @@ void ls(const UDSPInstruction opc)
// $ar0. Store value from register $acS.m to memory location pointed by
// register $ar3. Add corresponding indexing register $ix0 to addressing
// register $ar0 and increment $ar3.
void lsn(const UDSPInstruction opc)
void Interpreter::lsn(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0,
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
}
// LSM $axD.D, $acS.m
@@ -220,16 +213,18 @@ void lsn(const UDSPInstruction opc)
// $ar0. Store value from register $acS.m to memory location pointed by
// register $ar3. Add corresponding indexing register $ix3 to addressing
// register $ar3 and increment $ar0.
void lsm(const UDSPInstruction opc)
void Interpreter::lsm(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
}
// LSMN $axD.D, $acS.m
@@ -239,16 +234,19 @@ void lsm(const UDSPInstruction opc)
// register $ar3. Add corresponding indexing register $ix0 to addressing
// register $ar0 and add corresponding indexing register $ix3 to addressing
// register $ar3.
void lsnm(const UDSPInstruction opc)
void Interpreter::lsnm(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
WriteToBackLog(1, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
WriteToBackLog(2, DSP_REG_AR0,
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
}
// SL $acS.m, $axD.D
@@ -256,16 +254,17 @@ void lsnm(const UDSPInstruction opc)
// Store value from register $acS.m to memory location pointed by register
// $ar0. Load register $axD.D with value from memory pointed by register
// $ar3. Increment both $ar0 and $ar3.
void sl(const UDSPInstruction opc)
void Interpreter::sl(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
}
// SLN $acS.m, $axD.D
@@ -274,16 +273,18 @@ void sl(const UDSPInstruction opc)
// $ar0. Load register $axD.D with value from memory pointed by register
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
// and increment $ar3.
void sln(const UDSPInstruction opc)
void Interpreter::sln(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
WriteToBackLog(2, DSP_REG_AR0,
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
}
// SLM $acS.m, $axD.D
@@ -292,16 +293,18 @@ void sln(const UDSPInstruction opc)
// $ar0. Load register $axD.D with value from memory pointed by register
// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3
// and increment $ar0.
void slm(const UDSPInstruction opc)
void Interpreter::slm(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
}
// SLMN $acS.m, $axD.D
@@ -310,16 +313,19 @@ void slm(const UDSPInstruction opc)
// $ar0. Load register $axD.D with value from memory pointed by register
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
// and add corresponding indexing register $ix3 to addressing register $ar3.
void slnm(const UDSPInstruction opc)
void Interpreter::slnm(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1;
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
const u8 sreg = opc & 0x1;
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
auto& state = m_dsp_core.DSPState();
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(1, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
WriteToBackLog(2, DSP_REG_AR0,
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
}
// LD $ax0.d, $ax1.r, @$arS
@@ -334,228 +340,173 @@ void slnm(const UDSPInstruction opc)
// implemented yet)
// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not
// implemented yet)
void ld(const UDSPInstruction opc)
void Interpreter::ld(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
u8 sreg = opc & 0x3;
const u8 dreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = opc & 0x3;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}
// LDAX $axR, @$arS
// xxxx xxxx 11sr 0011
void ldax(const UDSPInstruction opc)
void Interpreter::ldax(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}
// LDN $ax0.d, $ax1.r, @$arS
// xxxx xxxx 11dr 01ss
void ldn(const UDSPInstruction opc)
void Interpreter::ldn(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
u8 sreg = opc & 0x3;
const u8 dreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = opc & 0x3;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}
// LDAXN $axR, @$arS
// xxxx xxxx 11sr 0111
void ldaxn(const UDSPInstruction opc)
void Interpreter::ldaxn(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}
// LDM $ax0.d, $ax1.r, @$arS
// xxxx xxxx 11dr 10ss
void ldm(const UDSPInstruction opc)
void Interpreter::ldm(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
u8 sreg = opc & 0x3;
const u8 dreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = opc & 0x3;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(3, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
}
// LDAXM $axR, @$arS
// xxxx xxxx 11sr 1011
void ldaxm(const UDSPInstruction opc)
void Interpreter::ldaxm(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(3, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
}
// LDNM $ax0.d, $ax1.r, @$arS
// xxxx xxxx 11dr 11ss
void ldnm(const UDSPInstruction opc)
void Interpreter::ldnm(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
u8 sreg = opc & 0x3;
const u8 dreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = opc & 0x3;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(3, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
}
// LDAXNM $axR, @$arS
// xxxx xxxx 11dr 1111
void ldaxnm(const UDSPInstruction opc)
void Interpreter::ldaxnm(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x1;
u8 rreg = (opc >> 4) & 0x1;
const u8 sreg = (opc >> 5) & 0x1;
const u8 rreg = (opc >> 4) & 0x1;
auto& state = m_dsp_core.DSPState();
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
else
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
WriteToBackLog(3, DSP_REG_AR3,
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
}
void nop(const UDSPInstruction opc)
void Interpreter::nop_ext(const UDSPInstruction)
{
}
} // namespace Interpreter::Ext
// 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.
// The ext op are writing their output into the backlog which is
// being applied to the real registers after the main op was executed
void ApplyWriteBackLog()
{
// always make sure to have an extra entry at the end w/ -1 to avoid
// infinitive loops
for (int i = 0; writeBackLogIdx[i] != -1; i++)
{
u16 value = writeBackLog[i];
#ifdef PRECISE_BACKLOG
value |= Interpreter::dsp_op_read_reg(writeBackLogIdx[i]);
#endif
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], value);
// Clear back log
writeBackLogIdx[i] = -1;
}
}
// This function is being called in the main op after all input regs were read
// and before it writes into any regs. This way we can always use bitwise or to
// apply the ext command output, because if the main op didn't change the value
// then 0 | ext output = ext output and if it did then bitwise or is still the
// right thing to do
// Only needed for cases when mainop and extended are modifying the same ACC
// Games are not doing that + in motorola (similar DSP) dox this is forbidden to do.
void ZeroWriteBackLog()
{
#ifdef PRECISE_BACKLOG
// always make sure to have an extra entry at the end w/ -1 to avoid
// infinitive loops
for (int i = 0; writeBackLogIdx[i] != -1; i++)
{
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
}
#endif
}
void ZeroWriteBackLogPreserveAcc(u8 acc)
{
#ifdef PRECISE_BACKLOG
for (int i = 0; writeBackLogIdx[i] != -1; i++)
{
// acc0
if ((acc == 0) &&
((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) ||
(writeBackLogIdx[i] == DSP_REG_ACH0)))
continue;
// acc1
if ((acc == 1) &&
((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) ||
(writeBackLogIdx[i] == DSP_REG_ACH1)))
continue;
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
}
#endif
}
} // namespace DSP
} // namespace DSP::Interpreter
@@ -1,41 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Copyright 2005 Duddie
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Core/DSP/DSPCommon.h"
// Extended opcode support.
// Many opcode have the lower 0xFF (some only 0x7f) free - there, an opcode extension
// can be stored.
namespace DSP::Interpreter::Ext
{
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(UDSPInstruction opc);
} // namespace DSP::Interpreter::Ext
@@ -4,8 +4,7 @@
//
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSP::Interpreter
@@ -16,15 +15,16 @@ namespace DSP::Interpreter
// CR[0-7] | M. That is, the upper 8 bits of the address are the
// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate.
// Note: pc+=2 in duddie's doc seems wrong
void srs(const UDSPInstruction opc)
void Interpreter::srs(const UDSPInstruction opc)
{
u8 reg = ((opc >> 8) & 0x7) + 0x18;
u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
auto& state = m_dsp_core.DSPState();
const auto reg = static_cast<u8>(((opc >> 8) & 0x7) + 0x18);
const auto addr = static_cast<u16>((state.r.cr << 8) | (opc & 0xFF));
if (reg >= DSP_REG_ACM0)
dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
state.WriteDMEM(addr, OpReadRegisterAndSaturate(reg - DSP_REG_ACM0));
else
dsp_dmem_write(addr, dsp_op_read_reg(reg));
state.WriteDMEM(addr, OpReadRegister(reg));
}
// LRS $(0x18+D), @M
@@ -32,40 +32,45 @@ void srs(const UDSPInstruction opc)
// Move value from data memory pointed by address CR[0-7] | M to register
// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits
// from CR, and the lower 8 bits are from the 8-bit immediate.
void lrs(const UDSPInstruction opc)
void Interpreter::lrs(const UDSPInstruction opc)
{
u8 reg = ((opc >> 8) & 0x7) + 0x18;
u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
dsp_op_write_reg(reg, dsp_dmem_read(addr));
dsp_conditional_extend_accum(reg);
auto& state = m_dsp_core.DSPState();
const auto reg = static_cast<u8>(((opc >> 8) & 0x7) + 0x18);
const auto addr = static_cast<u16>((state.r.cr << 8) | (opc & 0xFF));
OpWriteRegister(reg, state.ReadDMEM(addr));
ConditionalExtendAccum(reg);
}
// LR $D, @M
// 0000 0000 110d dddd
// mmmm mmmm mmmm mmmm
// Move value from data memory pointed by address M to register $D.
void lr(const UDSPInstruction opc)
void Interpreter::lr(const UDSPInstruction opc)
{
u8 reg = opc & 0x1F;
u16 addr = dsp_fetch_code();
u16 val = dsp_dmem_read(addr);
dsp_op_write_reg(reg, val);
dsp_conditional_extend_accum(reg);
auto& state = m_dsp_core.DSPState();
const u8 reg = opc & 0x1F;
const u16 addr = state.FetchInstruction();
const u16 val = state.ReadDMEM(addr);
OpWriteRegister(reg, val);
ConditionalExtendAccum(reg);
}
// SR @M, $S
// 0000 0000 111s ssss
// mmmm mmmm mmmm mmmm
// Store value from register $S to a memory pointed by address M.
void sr(const UDSPInstruction opc)
void Interpreter::sr(const UDSPInstruction opc)
{
u8 reg = opc & 0x1F;
u16 addr = dsp_fetch_code();
auto& state = m_dsp_core.DSPState();
const u8 reg = opc & 0x1F;
const u16 addr = state.FetchInstruction();
if (reg >= DSP_REG_ACM0)
dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
state.WriteDMEM(addr, OpReadRegisterAndSaturate(reg - DSP_REG_ACM0));
else
dsp_dmem_write(addr, dsp_op_read_reg(reg));
state.WriteDMEM(addr, OpReadRegister(reg));
}
// SI @M, #I
@@ -73,176 +78,189 @@ void sr(const UDSPInstruction opc)
// iiii iiii iiii iiii
// Store 16-bit immediate value I to a memory location pointed by address
// M (M is 8-bit value sign extended).
void si(const UDSPInstruction opc)
void Interpreter::si(const UDSPInstruction opc)
{
u16 addr = (s8)opc;
u16 imm = dsp_fetch_code();
dsp_dmem_write(addr, imm);
auto& state = m_dsp_core.DSPState();
const u16 addr = static_cast<u16>(static_cast<s8>(opc));
const u16 imm = state.FetchInstruction();
state.WriteDMEM(addr, imm);
}
// LRR $D, @$S
// 0001 1000 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
void lrr(const UDSPInstruction opc)
void Interpreter::lrr(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
u8 dreg = opc & 0x1f;
const u8 sreg = (opc >> 5) & 0x3;
const u8 dreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
dsp_op_write_reg(dreg, val);
dsp_conditional_extend_accum(dreg);
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
OpWriteRegister(dreg, val);
ConditionalExtendAccum(dreg);
}
// LRRD $D, @$S
// 0001 1000 1ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Decrement register $S.
void lrrd(const UDSPInstruction opc)
void Interpreter::lrrd(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
u8 dreg = opc & 0x1f;
const u8 sreg = (opc >> 5) & 0x3;
const u8 dreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
dsp_op_write_reg(dreg, val);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg);
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
OpWriteRegister(dreg, val);
ConditionalExtendAccum(dreg);
state.r.ar[sreg] = DecrementAddressRegister(sreg);
}
// LRRI $D, @$S
// 0001 1001 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Increment register $S.
void lrri(const UDSPInstruction opc)
void Interpreter::lrri(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
u8 dreg = opc & 0x1f;
const u8 sreg = (opc >> 5) & 0x3;
const u8 dreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
dsp_op_write_reg(dreg, val);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg);
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
OpWriteRegister(dreg, val);
ConditionalExtendAccum(dreg);
state.r.ar[sreg] = IncrementAddressRegister(sreg);
}
// LRRN $D, @$S
// 0001 1001 1ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Add indexing register $(0x4+S) to register $S.
void lrrn(const UDSPInstruction opc)
void Interpreter::lrrn(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
u8 dreg = opc & 0x1f;
const u8 sreg = (opc >> 5) & 0x3;
const u8 dreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
dsp_op_write_reg(dreg, val);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]);
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
OpWriteRegister(dreg, val);
ConditionalExtendAccum(dreg);
state.r.ar[sreg] = IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg]));
}
// SRR @$D, $S
// 0001 1010 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D.
void srr(const UDSPInstruction opc)
void Interpreter::srr(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
u8 sreg = opc & 0x1f;
const u8 dreg = (opc >> 5) & 0x3;
const u8 sreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
if (sreg >= DSP_REG_ACM0)
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
else
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
}
// SRRD @$D, $S
// 0001 1010 1dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Decrement register $D.
void srrd(const UDSPInstruction opc)
void Interpreter::srrd(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
u8 sreg = opc & 0x1f;
const u8 dreg = (opc >> 5) & 0x3;
const u8 sreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
if (sreg >= DSP_REG_ACM0)
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
else
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg);
state.r.ar[dreg] = DecrementAddressRegister(dreg);
}
// SRRI @$D, $S
// 0001 1011 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Increment register $D.
void srri(const UDSPInstruction opc)
void Interpreter::srri(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
u8 sreg = opc & 0x1f;
const u8 dreg = (opc >> 5) & 0x3;
const u8 sreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
if (sreg >= DSP_REG_ACM0)
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
else
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg);
state.r.ar[dreg] = IncrementAddressRegister(dreg);
}
// SRRN @$D, $S
// 0001 1011 1dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Add DSP_REG_IX0 register to register $D.
void srrn(const UDSPInstruction opc)
void Interpreter::srrn(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
u8 sreg = opc & 0x1f;
const u8 dreg = (opc >> 5) & 0x3;
const u8 sreg = opc & 0x1f;
auto& state = m_dsp_core.DSPState();
if (sreg >= DSP_REG_ACM0)
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
else
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]);
state.r.ar[dreg] = IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg]));
}
// ILRR $acD.m, @$arS
// 0000 001d 0001 00ss
// Move value from instruction memory pointed by addressing register
// $arS to mid accumulator register $acD.m.
void ilrr(const UDSPInstruction opc)
void Interpreter::ilrr(const UDSPInstruction opc)
{
u16 reg = opc & 0x3;
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
const u16 reg = opc & 0x3;
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
auto& state = m_dsp_core.DSPState();
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
dsp_conditional_extend_accum(dreg);
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
ConditionalExtendAccum(dreg);
}
// ILRRD $acD.m, @$arS
// 0000 001d 0001 01ss
// Move value from instruction memory pointed by addressing register
// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
void ilrrd(const UDSPInstruction opc)
void Interpreter::ilrrd(const UDSPInstruction opc)
{
u16 reg = opc & 0x3;
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
const u16 reg = opc & 0x3;
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
auto& state = m_dsp_core.DSPState();
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg);
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
ConditionalExtendAccum(dreg);
state.r.ar[reg] = DecrementAddressRegister(reg);
}
// ILRRI $acD.m, @$S
// 0000 001d 0001 10ss
// Move value from instruction memory pointed by addressing register
// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
void ilrri(const UDSPInstruction opc)
void Interpreter::ilrri(const UDSPInstruction opc)
{
u16 reg = opc & 0x3;
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
const u16 reg = opc & 0x3;
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
auto& state = m_dsp_core.DSPState();
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg);
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
ConditionalExtendAccum(dreg);
state.r.ar[reg] = IncrementAddressRegister(reg);
}
// ILRRN $acD.m, @$arS
@@ -250,13 +268,14 @@ void ilrri(const UDSPInstruction opc)
// Move value from instruction memory pointed by addressing register
// $arS to mid accumulator register $acD.m. Add corresponding indexing
// register $ixS to addressing register $arS.
void ilrrn(const UDSPInstruction opc)
void Interpreter::ilrrn(const UDSPInstruction opc)
{
u16 reg = opc & 0x3;
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
const u16 reg = opc & 0x3;
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
auto& state = m_dsp_core.DSPState();
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
dsp_conditional_extend_accum(dreg);
g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]);
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
ConditionalExtendAccum(dreg);
state.r.ar[reg] = IncreaseAddressRegister(reg, static_cast<s16>(state.r.ix[reg]));
}
} // namespace DSP::Interpreter
+60 -42
View File
@@ -5,7 +5,6 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
@@ -15,17 +14,17 @@ namespace DSP::Interpreter
// MRR $D, $S
// 0001 11dd ddds ssss
// Move value from register $S to register $D.
void mrr(const UDSPInstruction opc)
void Interpreter::mrr(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1f;
u8 dreg = (opc >> 5) & 0x1f;
const u8 sreg = opc & 0x1f;
const u8 dreg = (opc >> 5) & 0x1f;
if (sreg >= DSP_REG_ACM0)
dsp_op_write_reg(dreg, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
OpWriteRegister(dreg, OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
else
dsp_op_write_reg(dreg, dsp_op_read_reg(sreg));
OpWriteRegister(dreg, OpReadRegister(sreg));
dsp_conditional_extend_accum(dreg);
ConditionalExtendAccum(dreg);
}
// LRI $D, #I
@@ -37,23 +36,26 @@ void mrr(const UDSPInstruction opc)
// register, has a different behaviour in S40 mode if loaded to AC0.M: The
// value gets sign extended to the whole accumulator! This does not happen in
// S16 mode.
void lri(const UDSPInstruction opc)
void Interpreter::lri(const UDSPInstruction opc)
{
u8 reg = opc & 0x1F;
u16 imm = dsp_fetch_code();
dsp_op_write_reg(reg, imm);
dsp_conditional_extend_accum(reg);
auto& state = m_dsp_core.DSPState();
const u8 reg = opc & 0x1F;
const u16 imm = state.FetchInstruction();
OpWriteRegister(reg, imm);
ConditionalExtendAccum(reg);
}
// LRIS $(0x18+D), #I
// 0000 1ddd iiii iiii
// Load immediate value I (8-bit sign extended) to accumulator register.
void lris(const UDSPInstruction opc)
void Interpreter::lris(const UDSPInstruction opc)
{
u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;
u16 imm = (s8)opc;
dsp_op_write_reg(reg, imm);
dsp_conditional_extend_accum(reg);
const u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;
const u16 imm = static_cast<u16>(static_cast<s8>(opc));
OpWriteRegister(reg, imm);
ConditionalExtendAccum(reg);
}
//----
@@ -63,7 +65,7 @@ void lris(const UDSPInstruction opc)
// No operation, but can be extended with extended opcode.
// This opcode is supposed to do nothing - it's used if you want to use
// an opcode extension but not do anything. At least according to duddie.
void nx(const UDSPInstruction opc)
void Interpreter::nx(const UDSPInstruction)
{
ZeroWriteBackLog();
}
@@ -73,38 +75,48 @@ void nx(const UDSPInstruction opc)
// DAR $arD
// 0000 0000 0000 01dd
// Decrement address register $arD.
void dar(const UDSPInstruction opc)
void Interpreter::dar(const UDSPInstruction opc)
{
g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3);
auto& state = m_dsp_core.DSPState();
const u16 index = opc & 3;
state.r.ar[index] = DecrementAddressRegister(index);
}
// IAR $arD
// 0000 0000 0000 10dd
// Increment address register $arD.
void iar(const UDSPInstruction opc)
void Interpreter::iar(const UDSPInstruction opc)
{
g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3);
auto& state = m_dsp_core.DSPState();
const u16 index = opc & 3;
state.r.ar[index] = IncrementAddressRegister(index);
}
// SUBARN $arD
// 0000 0000 0000 11dd
// Subtract indexing register $ixD from an addressing register $arD.
// used only in IPL-NTSC ucode
void subarn(const UDSPInstruction opc)
void Interpreter::subarn(const UDSPInstruction opc)
{
u8 dreg = opc & 0x3;
g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]);
auto& state = m_dsp_core.DSPState();
const u8 dreg = opc & 0x3;
state.r.ar[dreg] = DecreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg]));
}
// ADDARN $arD, $ixS
// 0000 0000 0001 ssdd
// Adds indexing register $ixS to an addressing register $arD.
// It is critical for the Zelda ucode that this one wraps correctly.
void addarn(const UDSPInstruction opc)
void Interpreter::addarn(const UDSPInstruction opc)
{
u8 dreg = opc & 0x3;
u8 sreg = (opc >> 2) & 0x3;
g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]);
auto& state = m_dsp_core.DSPState();
const u8 dreg = opc & 0x3;
const u8 sreg = (opc >> 2) & 0x3;
state.r.ar[dreg] = IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[sreg]));
}
//----
@@ -113,45 +125,51 @@ void addarn(const UDSPInstruction opc)
// 0001 0010 aaaa aiii
// bit of status register $sr. Bit number is calculated by adding 6 to
// immediate value I.
void sbclr(const UDSPInstruction opc)
void Interpreter::sbclr(const UDSPInstruction opc)
{
u8 bit = (opc & 0x7) + 6;
g_dsp.r.sr &= ~(1 << bit);
auto& state = m_dsp_core.DSPState();
const u8 bit = (opc & 0x7) + 6;
state.r.sr &= ~(1U << bit);
}
// SBSET #I
// 0001 0011 aaaa aiii
// Set bit of status register $sr. Bit number is calculated by adding 6 to
// immediate value I.
void sbset(const UDSPInstruction opc)
void Interpreter::sbset(const UDSPInstruction opc)
{
u8 bit = (opc & 0x7) + 6;
g_dsp.r.sr |= (1 << bit);
auto& state = m_dsp_core.DSPState();
const u8 bit = (opc & 0x7) + 6;
state.r.sr |= (1U << bit);
}
// This is a bunch of flag setters, flipping bits in SR.
void srbith(const UDSPInstruction opc)
void Interpreter::srbith(const UDSPInstruction opc)
{
auto& state = m_dsp_core.DSPState();
ZeroWriteBackLog();
switch ((opc >> 8) & 0x7)
{
case 2: // M2
g_dsp.r.sr &= ~SR_MUL_MODIFY;
state.r.sr &= ~SR_MUL_MODIFY;
break;
case 3: // M0
g_dsp.r.sr |= SR_MUL_MODIFY;
state.r.sr |= SR_MUL_MODIFY;
break;
case 4: // CLR15
g_dsp.r.sr &= ~SR_MUL_UNSIGNED;
state.r.sr &= ~SR_MUL_UNSIGNED;
break;
case 5: // SET15
g_dsp.r.sr |= SR_MUL_UNSIGNED;
state.r.sr |= SR_MUL_UNSIGNED;
break;
case 6: // SET16 (CLR40)
g_dsp.r.sr &= ~SR_40_MODE_BIT;
state.r.sr &= ~SR_40_MODE_BIT;
break;
case 7: // SET40
g_dsp.r.sr |= SR_40_MODE_BIT;
state.r.sr |= SR_40_MODE_BIT;
break;
default:
break;
@@ -13,62 +13,6 @@
namespace DSP::Interpreter
{
namespace
{
// Only MULX family instructions have unsigned/mixed support.
s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign)
{
s64 prod;
if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // unsigned
prod = (u32)(a * b);
else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // mixed
prod = a * (s16)b;
else
prod = (s16)a * (s16)b; // signed
// Conditionally multiply by 2.
if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
prod <<= 1;
return prod;
}
s64 dsp_multiply(u16 a, u16 b, u8 sign = 0)
{
s64 prod = dsp_get_multiply_prod(a, b, sign);
return prod;
}
s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0)
{
s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign);
return prod;
}
s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0)
{
s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign);
return prod;
}
s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2)
{
s64 result;
if ((axh0 == 0) && (axh1 == 0))
result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used
else if ((axh0 == 0) && (axh1 == 1))
result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1
else if ((axh0 == 1) && (axh1 == 0))
result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0
else
result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
return result;
}
} // Anonymous namespace
// CLRP
// 1000 0100 xxxx xxxx
// Clears product register $prod.
@@ -78,14 +22,15 @@ s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2)
//
// It's not ok, to just zero all of them, correct values should be set because of
// direct use of prod regs by AX/AXWII (look @that part of ucode).
void clrp(const UDSPInstruction opc)
void Interpreter::clrp(const UDSPInstruction)
{
ZeroWriteBackLog();
g_dsp.r.prod.l = 0x0000;
g_dsp.r.prod.m = 0xfff0;
g_dsp.r.prod.h = 0x00ff;
g_dsp.r.prod.m2 = 0x0010;
auto& state = m_dsp_core.DSPState();
state.r.prod.l = 0x0000;
state.r.prod.m = 0xfff0;
state.r.prod.h = 0x00ff;
state.r.prod.m2 = 0x0010;
}
// TSTPROD
@@ -93,10 +38,10 @@ void clrp(const UDSPInstruction opc)
// Test prod regs value.
//
// flags out: --xx xx0x
void tstprod(const UDSPInstruction opc)
void Interpreter::tstprod(const UDSPInstruction)
{
s64 prod = dsp_get_long_prod();
Update_SR_Register64(prod);
const s64 prod = GetLongProduct();
UpdateSR64(prod);
ZeroWriteBackLog();
}
@@ -107,16 +52,15 @@ void tstprod(const UDSPInstruction opc)
// Moves multiply product from $prod register to accumulator $acD register.
//
// flags out: --xx xx0x
void movp(const UDSPInstruction opc)
void Interpreter::movp(const UDSPInstruction opc)
{
u8 dreg = (opc >> 8) & 0x1;
s64 acc = dsp_get_long_prod();
const u8 dreg = (opc >> 8) & 0x1;
const s64 acc = GetLongProduct();
ZeroWriteBackLog();
dsp_set_long_acc(dreg, acc);
Update_SR_Register64(acc);
SetLongAcc(dreg, acc);
UpdateSR64(acc);
}
// MOVNP $acD
@@ -125,16 +69,15 @@ void movp(const UDSPInstruction opc)
// $acD register.
//
// flags out: --xx xx0x
void movnp(const UDSPInstruction opc)
void Interpreter::movnp(const UDSPInstruction opc)
{
u8 dreg = (opc >> 8) & 0x1;
s64 acc = -dsp_get_long_prod();
const u8 dreg = (opc >> 8) & 0x1;
const s64 acc = -GetLongProduct();
ZeroWriteBackLog();
dsp_set_long_acc(dreg, acc);
Update_SR_Register64(acc);
SetLongAcc(dreg, acc);
UpdateSR64(acc);
}
// MOVPZ $acD
@@ -143,16 +86,15 @@ void movnp(const UDSPInstruction opc)
// register and sets (rounds) $acD.l to 0
//
// flags out: --xx xx0x
void movpz(const UDSPInstruction opc)
void Interpreter::movpz(const UDSPInstruction opc)
{
u8 dreg = (opc >> 8) & 0x01;
s64 acc = dsp_get_long_prod_round_prodl();
const u8 dreg = (opc >> 8) & 0x01;
const s64 acc = GetLongProductRounded();
ZeroWriteBackLog();
dsp_set_long_acc(dreg, acc);
Update_SR_Register64(acc);
SetLongAcc(dreg, acc);
UpdateSR64(acc);
}
// ADDPAXZ $acD, $axS
@@ -162,21 +104,21 @@ void movpz(const UDSPInstruction opc)
//
// TODO: ugly code and still small error here (+/- 1 in .m - randomly)
// flags out: --xx xx0x
void addpaxz(const UDSPInstruction opc)
void Interpreter::addpaxz(const UDSPInstruction opc)
{
u8 dreg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 9) & 0x1;
const u8 dreg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 9) & 0x1;
s64 oldprod = dsp_get_long_prod();
s64 prod = dsp_get_long_prod_round_prodl();
s64 ax = dsp_get_long_acx(sreg);
const s64 oldprod = GetLongProduct();
const s64 prod = GetLongProductRounded();
const s64 ax = GetLongACX(sreg);
s64 res = prod + (ax & ~0xffff);
ZeroWriteBackLog();
dsp_set_long_acc(dreg, res);
res = dsp_get_long_acc(dreg);
Update_SR_Register64(res, isCarry(oldprod, res), false);
SetLongAcc(dreg, res);
res = GetLongAcc(dreg);
UpdateSR64(res, isCarry(oldprod, res), false);
}
//----
@@ -184,13 +126,14 @@ void addpaxz(const UDSPInstruction opc)
// MULAXH
// 1000 0011 xxxx xxxx
// Multiply $ax0.h by $ax0.h
void mulaxh(const UDSPInstruction opc)
void Interpreter::mulaxh(const UDSPInstruction)
{
s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0));
const s16 value = GetAXHigh(0);
const s64 prod = Multiply(value, value);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
//----
@@ -199,17 +142,16 @@ void mulaxh(const UDSPInstruction opc)
// 1001 s000 xxxx xxxx
// Multiply low part $axS.l of secondary accumulator $axS by high part
// $axS.h of secondary accumulator $axS (treat them both as signed).
void mul(const UDSPInstruction opc)
void Interpreter::mul(const UDSPInstruction opc)
{
u8 sreg = (opc >> 11) & 0x1;
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply(axh, axl);
const u8 sreg = (opc >> 11) & 0x1;
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = Multiply(axh, axl);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MULAC $axS.l, $axS.h, $acR
@@ -219,21 +161,21 @@ void mul(const UDSPInstruction opc)
// accumulator $axS (treat them both as signed).
//
// flags out: --xx xx0x
void mulac(const UDSPInstruction opc)
void Interpreter::mulac(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 11) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 11) & 0x1;
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply(axl, axh);
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = Multiply(axl, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULMV $axS.l, $axS.h, $acR
@@ -243,21 +185,21 @@ void mulac(const UDSPInstruction opc)
// accumulator $axS (treat them both as signed).
//
// flags out: --xx xx0x
void mulmv(const UDSPInstruction opc)
void Interpreter::mulmv(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 sreg = ((opc >> 11) & 0x1);
const u8 rreg = (opc >> 8) & 0x1;
const u8 sreg = ((opc >> 11) & 0x1);
s64 acc = dsp_get_long_prod();
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply(axl, axh);
const s64 acc = GetLongProduct();
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = Multiply(axl, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULMVZ $axS.l, $axS.h, $acR
@@ -268,21 +210,21 @@ void mulmv(const UDSPInstruction opc)
// them both as signed).
//
// flags out: --xx xx0x
void mulmvz(const UDSPInstruction opc)
void Interpreter::mulmvz(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 11) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 11) & 0x1;
s64 acc = dsp_get_long_prod_round_prodl();
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply(axl, axh);
const s64 acc = GetLongProductRounded();
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = Multiply(axl, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
//----
@@ -291,18 +233,18 @@ void mulmvz(const UDSPInstruction opc)
// 101s t000 xxxx xxxx
// Multiply one part $ax0 by one part $ax1.
// Part is selected by S and T bits. Zero selects low part, one selects high part.
void mulx(const UDSPInstruction opc)
void Interpreter::mulx(const UDSPInstruction opc)
{
u8 treg = ((opc >> 11) & 0x1);
u8 sreg = ((opc >> 12) & 0x1);
const u8 treg = ((opc >> 11) & 0x1);
const u8 sreg = ((opc >> 12) & 0x1);
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MULXAC $ax0.S, $ax1.T, $acR
@@ -312,22 +254,22 @@ void mulx(const UDSPInstruction opc)
// T bits. Zero selects low part, one selects high part.
//
// flags out: --xx xx0x
void mulxac(const UDSPInstruction opc)
void Interpreter::mulxac(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULXMV $ax0.S, $ax1.T, $acR
@@ -337,22 +279,22 @@ void mulxac(const UDSPInstruction opc)
// T bits. Zero selects low part, one selects high part.
//
// flags out: --xx xx0x
void mulxmv(const UDSPInstruction opc)
void Interpreter::mulxmv(const UDSPInstruction opc)
{
u8 rreg = ((opc >> 8) & 0x1);
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = ((opc >> 8) & 0x1);
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_prod();
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
const s64 acc = GetLongProduct();
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULXMVZ $ax0.S, $ax1.T, $acR
@@ -363,22 +305,22 @@ void mulxmv(const UDSPInstruction opc)
// one selects high part.
//
// flags out: --xx xx0x
void mulxmvz(const UDSPInstruction opc)
void Interpreter::mulxmvz(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_prod_round_prodl();
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
const s64 acc = GetLongProductRounded();
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
//----
@@ -387,18 +329,18 @@ void mulxmvz(const UDSPInstruction opc)
// 110s t000 xxxx xxxx
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
// secondary accumulator $axS (treat them both as signed).
void mulc(const UDSPInstruction opc)
void Interpreter::mulc(const UDSPInstruction opc)
{
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply(accm, axh);
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = Multiply(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MULCAC $acS.m, $axT.h, $acR
@@ -408,22 +350,22 @@ void mulc(const UDSPInstruction opc)
// register before multiplication to accumulator $acR.
//
// flags out: --xx xx0x
void mulcac(const UDSPInstruction opc)
void Interpreter::mulcac(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply(accm, axh);
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = Multiply(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULCMV $acS.m, $axT.h, $acR
@@ -434,22 +376,22 @@ void mulcac(const UDSPInstruction opc)
// possible mistake in duddie's doc axT.h rather than axS.h
//
// flags out: --xx xx0x
void mulcmv(const UDSPInstruction opc)
void Interpreter::mulcmv(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_prod();
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply(accm, axh);
const s64 acc = GetLongProduct();
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = Multiply(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
// MULCMVZ $acS.m, $axT.h, $acR
@@ -461,22 +403,22 @@ void mulcmv(const UDSPInstruction opc)
// accumulator $acR.l to zero.
//
// flags out: --xx xx0x
void mulcmvz(const UDSPInstruction opc)
void Interpreter::mulcmvz(const UDSPInstruction opc)
{
u8 rreg = (opc >> 8) & 0x1;
u8 treg = (opc >> 11) & 0x1;
u8 sreg = (opc >> 12) & 0x1;
const u8 rreg = (opc >> 8) & 0x1;
const u8 treg = (opc >> 11) & 0x1;
const u8 sreg = (opc >> 12) & 0x1;
s64 acc = dsp_get_long_prod_round_prodl();
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply(accm, axh);
const s64 acc = GetLongProductRounded();
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = Multiply(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
dsp_set_long_acc(rreg, acc);
Update_SR_Register64(dsp_get_long_acc(rreg));
SetLongProduct(prod);
SetLongAcc(rreg, acc);
UpdateSR64(GetLongAcc(rreg));
}
//----
@@ -486,18 +428,18 @@ void mulcmvz(const UDSPInstruction opc)
// Multiply one part of secondary accumulator $ax0 (selected by S) by
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
// signed) and add result to product register.
void maddx(const UDSPInstruction opc)
void Interpreter::maddx(const UDSPInstruction opc)
{
u8 treg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 9) & 0x1;
const u8 treg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 9) & 0x1;
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_add(val1, val2);
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplyAdd(val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MSUBX $(0x18+S*2), $(0x19+T*2)
@@ -505,18 +447,18 @@ void maddx(const UDSPInstruction opc)
// Multiply one part of secondary accumulator $ax0 (selected by S) by
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
// signed) and subtract result from product register.
void msubx(const UDSPInstruction opc)
void Interpreter::msubx(const UDSPInstruction opc)
{
u8 treg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 9) & 0x1;
const u8 treg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 9) & 0x1;
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
s64 prod = dsp_multiply_sub(val1, val2);
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
const s64 prod = MultiplySub(val1, val2);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MADDC $acS.m, $axT.h
@@ -524,18 +466,18 @@ void msubx(const UDSPInstruction opc)
// Multiply middle part of accumulator $acS.m by high part of secondary
// accumulator $axT.h (treat them both as signed) and add result to product
// register.
void maddc(const UDSPInstruction opc)
void Interpreter::maddc(const UDSPInstruction opc)
{
u8 treg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 9) & 0x1;
const u8 treg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 9) & 0x1;
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply_add(accm, axh);
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = MultiplyAdd(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MSUBC $acS.m, $axT.h
@@ -543,18 +485,18 @@ void maddc(const UDSPInstruction opc)
// Multiply middle part of accumulator $acS.m by high part of secondary
// accumulator $axT.h (treat them both as signed) and subtract result from
// product register.
void msubc(const UDSPInstruction opc)
void Interpreter::msubc(const UDSPInstruction opc)
{
u8 treg = (opc >> 8) & 0x1;
u8 sreg = (opc >> 9) & 0x1;
const u8 treg = (opc >> 8) & 0x1;
const u8 sreg = (opc >> 9) & 0x1;
u16 accm = dsp_get_acc_m(sreg);
u16 axh = dsp_get_ax_h(treg);
s64 prod = dsp_multiply_sub(accm, axh);
const u16 accm = GetAccMid(sreg);
const u16 axh = GetAXHigh(treg);
const s64 prod = MultiplySub(accm, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MADD $axS.l, $axS.h
@@ -562,17 +504,16 @@ void msubc(const UDSPInstruction opc)
// Multiply low part $axS.l of secondary accumulator $axS by high part
// $axS.h of secondary accumulator $axS (treat them both as signed) and add
// result to product register.
void madd(const UDSPInstruction opc)
void Interpreter::madd(const UDSPInstruction opc)
{
u8 sreg = (opc >> 8) & 0x1;
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply_add(axl, axh);
const u8 sreg = (opc >> 8) & 0x1;
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = MultiplyAdd(axl, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
// MSUB $axS.l, $axS.h
@@ -580,16 +521,15 @@ void madd(const UDSPInstruction opc)
// Multiply low part $axS.l of secondary accumulator $axS by high part
// $axS.h of secondary accumulator $axS (treat them both as signed) and
// subtract result from product register.
void msub(const UDSPInstruction opc)
void Interpreter::msub(const UDSPInstruction opc)
{
u8 sreg = (opc >> 8) & 0x1;
u16 axl = dsp_get_ax_l(sreg);
u16 axh = dsp_get_ax_h(sreg);
s64 prod = dsp_multiply_sub(axl, axh);
const u8 sreg = (opc >> 8) & 0x1;
const u16 axl = GetAXLow(sreg);
const u16 axh = GetAXHigh(sreg);
const s64 prod = MultiplySub(axl, axh);
ZeroWriteBackLog();
dsp_set_long_prod(prod);
SetLongProduct(prod);
}
} // namespace DSP::Interpreter
+151 -152
View File
@@ -8,7 +8,6 @@
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSP::Interpreter
@@ -23,216 +22,216 @@ struct InterpreterOpInfo
// clang-format off
constexpr std::array<InterpreterOpInfo, 124> s_opcodes
{{
{0x0000, 0xfffc, nop},
{0x0000, 0xfffc, &Interpreter::nop},
{0x0004, 0xfffc, dar},
{0x0008, 0xfffc, iar},
{0x000c, 0xfffc, subarn},
{0x0010, 0xfff0, addarn},
{0x0004, 0xfffc, &Interpreter::dar},
{0x0008, 0xfffc, &Interpreter::iar},
{0x000c, 0xfffc, &Interpreter::subarn},
{0x0010, 0xfff0, &Interpreter::addarn},
{0x0021, 0xffff, halt},
{0x0021, 0xffff, &Interpreter::halt},
{0x02d0, 0xfff0, ret},
{0x02d0, 0xfff0, &Interpreter::ret},
{0x02ff, 0xffff, rti},
{0x02ff, 0xffff, &Interpreter::rti},
{0x02b0, 0xfff0, call},
{0x02b0, 0xfff0, &Interpreter::call},
{0x0270, 0xfff0, ifcc},
{0x0270, 0xfff0, &Interpreter::ifcc},
{0x0290, 0xfff0, jcc},
{0x0290, 0xfff0, &Interpreter::jcc},
{0x1700, 0xff10, jmprcc},
{0x1700, 0xff10, &Interpreter::jmprcc},
{0x1710, 0xff10, callr},
{0x1710, 0xff10, &Interpreter::callr},
{0x1200, 0xff00, sbclr},
{0x1300, 0xff00, sbset},
{0x1200, 0xff00, &Interpreter::sbclr},
{0x1300, 0xff00, &Interpreter::sbset},
{0x1400, 0xfec0, lsl},
{0x1440, 0xfec0, lsr},
{0x1480, 0xfec0, asl},
{0x14c0, 0xfec0, asr},
{0x1400, 0xfec0, &Interpreter::lsl},
{0x1440, 0xfec0, &Interpreter::lsr},
{0x1480, 0xfec0, &Interpreter::asl},
{0x14c0, 0xfec0, &Interpreter::asr},
// these two were discovered by ector
{0x02ca, 0xffff, lsrn},
{0x02cb, 0xffff, asrn},
{0x02ca, 0xffff, &Interpreter::lsrn},
{0x02cb, 0xffff, &Interpreter::asrn},
{0x0080, 0xffe0, lri},
{0x00c0, 0xffe0, lr},
{0x00e0, 0xffe0, sr},
{0x0080, 0xffe0, &Interpreter::lri},
{0x00c0, 0xffe0, &Interpreter::lr},
{0x00e0, 0xffe0, &Interpreter::sr},
{0x1c00, 0xfc00, mrr},
{0x1c00, 0xfc00, &Interpreter::mrr},
{0x1600, 0xff00, si},
{0x1600, 0xff00, &Interpreter::si},
{0x0400, 0xfe00, addis},
{0x0600, 0xfe00, cmpis},
{0x0800, 0xf800, lris},
{0x0400, 0xfe00, &Interpreter::addis},
{0x0600, 0xfe00, &Interpreter::cmpis},
{0x0800, 0xf800, &Interpreter::lris},
{0x0200, 0xfeff, addi},
{0x0220, 0xfeff, xori},
{0x0240, 0xfeff, andi},
{0x0260, 0xfeff, ori},
{0x0280, 0xfeff, cmpi},
{0x0200, 0xfeff, &Interpreter::addi},
{0x0220, 0xfeff, &Interpreter::xori},
{0x0240, 0xfeff, &Interpreter::andi},
{0x0260, 0xfeff, &Interpreter::ori},
{0x0280, 0xfeff, &Interpreter::cmpi},
{0x02a0, 0xfeff, andf},
{0x02c0, 0xfeff, andcf},
{0x02a0, 0xfeff, &Interpreter::andf},
{0x02c0, 0xfeff, &Interpreter::andcf},
{0x0210, 0xfefc, ilrr},
{0x0214, 0xfefc, ilrrd},
{0x0218, 0xfefc, ilrri},
{0x021c, 0xfefc, ilrrn},
{0x0210, 0xfefc, &Interpreter::ilrr},
{0x0214, 0xfefc, &Interpreter::ilrrd},
{0x0218, 0xfefc, &Interpreter::ilrri},
{0x021c, 0xfefc, &Interpreter::ilrrn},
// LOOPS
{0x0040, 0xffe0, loop},
{0x0060, 0xffe0, bloop},
{0x1000, 0xff00, loopi},
{0x1100, 0xff00, bloopi},
{0x0040, 0xffe0, &Interpreter::loop},
{0x0060, 0xffe0, &Interpreter::bloop},
{0x1000, 0xff00, &Interpreter::loopi},
{0x1100, 0xff00, &Interpreter::bloopi},
// load and store value pointed by indexing reg and increment; LRR/SRR variants
{0x1800, 0xff80, lrr},
{0x1880, 0xff80, lrrd},
{0x1900, 0xff80, lrri},
{0x1980, 0xff80, lrrn},
{0x1800, 0xff80, &Interpreter::lrr},
{0x1880, 0xff80, &Interpreter::lrrd},
{0x1900, 0xff80, &Interpreter::lrri},
{0x1980, 0xff80, &Interpreter::lrrn},
{0x1a00, 0xff80, srr},
{0x1a80, 0xff80, srrd},
{0x1b00, 0xff80, srri},
{0x1b80, 0xff80, srrn},
{0x1a00, 0xff80, &Interpreter::srr},
{0x1a80, 0xff80, &Interpreter::srrd},
{0x1b00, 0xff80, &Interpreter::srri},
{0x1b80, 0xff80, &Interpreter::srrn},
// 2
{0x2000, 0xf800, lrs},
{0x2800, 0xf800, srs},
{0x2000, 0xf800, &Interpreter::lrs},
{0x2800, 0xf800, &Interpreter::srs},
// opcodes that can be extended
// 3 - main opcode defined by 9 bits, extension defined by last 7 bits!!
{0x3000, 0xfc80, xorr},
{0x3400, 0xfc80, andr},
{0x3800, 0xfc80, orr},
{0x3c00, 0xfe80, andc},
{0x3e00, 0xfe80, orc},
{0x3080, 0xfe80, xorc},
{0x3280, 0xfe80, notc},
{0x3480, 0xfc80, lsrnrx},
{0x3880, 0xfc80, asrnrx},
{0x3c80, 0xfe80, lsrnr},
{0x3e80, 0xfe80, asrnr},
{0x3000, 0xfc80, &Interpreter::xorr},
{0x3400, 0xfc80, &Interpreter::andr},
{0x3800, 0xfc80, &Interpreter::orr},
{0x3c00, 0xfe80, &Interpreter::andc},
{0x3e00, 0xfe80, &Interpreter::orc},
{0x3080, 0xfe80, &Interpreter::xorc},
{0x3280, 0xfe80, &Interpreter::notc},
{0x3480, 0xfc80, &Interpreter::lsrnrx},
{0x3880, 0xfc80, &Interpreter::asrnrx},
{0x3c80, 0xfe80, &Interpreter::lsrnr},
{0x3e80, 0xfe80, &Interpreter::asrnr},
// 4
{0x4000, 0xf800, addr},
{0x4800, 0xfc00, addax},
{0x4c00, 0xfe00, add},
{0x4e00, 0xfe00, addp},
{0x4000, 0xf800, &Interpreter::addr},
{0x4800, 0xfc00, &Interpreter::addax},
{0x4c00, 0xfe00, &Interpreter::add},
{0x4e00, 0xfe00, &Interpreter::addp},
// 5
{0x5000, 0xf800, subr},
{0x5800, 0xfc00, subax},
{0x5c00, 0xfe00, sub},
{0x5e00, 0xfe00, subp},
{0x5000, 0xf800, &Interpreter::subr},
{0x5800, 0xfc00, &Interpreter::subax},
{0x5c00, 0xfe00, &Interpreter::sub},
{0x5e00, 0xfe00, &Interpreter::subp},
// 6
{0x6000, 0xf800, movr},
{0x6800, 0xfc00, movax},
{0x6c00, 0xfe00, mov},
{0x6e00, 0xfe00, movp},
{0x6000, 0xf800, &Interpreter::movr},
{0x6800, 0xfc00, &Interpreter::movax},
{0x6c00, 0xfe00, &Interpreter::mov},
{0x6e00, 0xfe00, &Interpreter::movp},
// 7
{0x7000, 0xfc00, addaxl},
{0x7400, 0xfe00, incm},
{0x7600, 0xfe00, inc},
{0x7800, 0xfe00, decm},
{0x7a00, 0xfe00, dec},
{0x7c00, 0xfe00, neg},
{0x7e00, 0xfe00, movnp},
{0x7000, 0xfc00, &Interpreter::addaxl},
{0x7400, 0xfe00, &Interpreter::incm},
{0x7600, 0xfe00, &Interpreter::inc},
{0x7800, 0xfe00, &Interpreter::decm},
{0x7a00, 0xfe00, &Interpreter::dec},
{0x7c00, 0xfe00, &Interpreter::neg},
{0x7e00, 0xfe00, &Interpreter::movnp},
// 8
{0x8000, 0xf700, nx},
{0x8100, 0xf700, clr},
{0x8200, 0xff00, cmp},
{0x8300, 0xff00, mulaxh},
{0x8400, 0xff00, clrp},
{0x8500, 0xff00, tstprod},
{0x8600, 0xfe00, tstaxh},
{0x8a00, 0xff00, srbith},
{0x8b00, 0xff00, srbith},
{0x8c00, 0xff00, srbith},
{0x8d00, 0xff00, srbith},
{0x8e00, 0xff00, srbith},
{0x8f00, 0xff00, srbith},
{0x8000, 0xf700, &Interpreter::nx},
{0x8100, 0xf700, &Interpreter::clr},
{0x8200, 0xff00, &Interpreter::cmp},
{0x8300, 0xff00, &Interpreter::mulaxh},
{0x8400, 0xff00, &Interpreter::clrp},
{0x8500, 0xff00, &Interpreter::tstprod},
{0x8600, 0xfe00, &Interpreter::tstaxh},
{0x8a00, 0xff00, &Interpreter::srbith},
{0x8b00, 0xff00, &Interpreter::srbith},
{0x8c00, 0xff00, &Interpreter::srbith},
{0x8d00, 0xff00, &Interpreter::srbith},
{0x8e00, 0xff00, &Interpreter::srbith},
{0x8f00, 0xff00, &Interpreter::srbith},
// 9
{0x9000, 0xf700, mul},
{0x9100, 0xf700, asr16},
{0x9200, 0xf600, mulmvz},
{0x9400, 0xf600, mulac},
{0x9600, 0xf600, mulmv},
{0x9000, 0xf700, &Interpreter::mul},
{0x9100, 0xf700, &Interpreter::asr16},
{0x9200, 0xf600, &Interpreter::mulmvz},
{0x9400, 0xf600, &Interpreter::mulac},
{0x9600, 0xf600, &Interpreter::mulmv},
// A-B
{0xa000, 0xe700, mulx},
{0xa100, 0xf700, abs},
{0xa200, 0xe600, mulxmvz},
{0xa400, 0xe600, mulxac},
{0xa600, 0xe600, mulxmv},
{0xb100, 0xf700, tst},
{0xa000, 0xe700, &Interpreter::mulx},
{0xa100, 0xf700, &Interpreter::abs},
{0xa200, 0xe600, &Interpreter::mulxmvz},
{0xa400, 0xe600, &Interpreter::mulxac},
{0xa600, 0xe600, &Interpreter::mulxmv},
{0xb100, 0xf700, &Interpreter::tst},
// C-D
{0xc000, 0xe700, mulc},
{0xc100, 0xe700, cmpar},
{0xc200, 0xe600, mulcmvz},
{0xc400, 0xe600, mulcac},
{0xc600, 0xe600, mulcmv},
{0xc000, 0xe700, &Interpreter::mulc},
{0xc100, 0xe700, &Interpreter::cmpar},
{0xc200, 0xe600, &Interpreter::mulcmvz},
{0xc400, 0xe600, &Interpreter::mulcac},
{0xc600, 0xe600, &Interpreter::mulcmv},
// E
{0xe000, 0xfc00, maddx},
{0xe400, 0xfc00, msubx},
{0xe800, 0xfc00, maddc},
{0xec00, 0xfc00, msubc},
{0xe000, 0xfc00, &Interpreter::maddx},
{0xe400, 0xfc00, &Interpreter::msubx},
{0xe800, 0xfc00, &Interpreter::maddc},
{0xec00, 0xfc00, &Interpreter::msubc},
// F
{0xf000, 0xfe00, lsl16},
{0xf200, 0xfe00, madd},
{0xf400, 0xfe00, lsr16},
{0xf600, 0xfe00, msub},
{0xf800, 0xfc00, addpaxz},
{0xfc00, 0xfe00, clrl},
{0xfe00, 0xfe00, movpz},
{0xf000, 0xfe00, &Interpreter::lsl16},
{0xf200, 0xfe00, &Interpreter::madd},
{0xf400, 0xfe00, &Interpreter::lsr16},
{0xf600, 0xfe00, &Interpreter::msub},
{0xf800, 0xfc00, &Interpreter::addpaxz},
{0xfc00, 0xfe00, &Interpreter::clrl},
{0xfe00, 0xfe00, &Interpreter::movpz},
}};
constexpr std::array<InterpreterOpInfo, 25> s_opcodes_ext
{{
{0x0000, 0x00fc, Ext::nop},
{0x0000, 0x00fc, &Interpreter::nop_ext},
{0x0004, 0x00fc, Ext::dr},
{0x0008, 0x00fc, Ext::ir},
{0x000c, 0x00fc, Ext::nr},
{0x0010, 0x00f0, Ext::mv},
{0x0004, 0x00fc, &Interpreter::dr},
{0x0008, 0x00fc, &Interpreter::ir},
{0x000c, 0x00fc, &Interpreter::nr},
{0x0010, 0x00f0, &Interpreter::mv},
{0x0020, 0x00e4, Ext::s},
{0x0024, 0x00e4, Ext::sn},
{0x0020, 0x00e4, &Interpreter::s},
{0x0024, 0x00e4, &Interpreter::sn},
{0x0040, 0x00c4, Ext::l},
{0x0044, 0x00c4, Ext::ln},
{0x0040, 0x00c4, &Interpreter::l},
{0x0044, 0x00c4, &Interpreter::ln},
{0x0080, 0x00ce, Ext::ls},
{0x0082, 0x00ce, Ext::sl},
{0x0084, 0x00ce, Ext::lsn},
{0x0086, 0x00ce, Ext::sln},
{0x0088, 0x00ce, Ext::lsm},
{0x008a, 0x00ce, Ext::slm},
{0x008c, 0x00ce, Ext::lsnm},
{0x008e, 0x00ce, Ext::slnm},
{0x0080, 0x00ce, &Interpreter::ls},
{0x0082, 0x00ce, &Interpreter::sl},
{0x0084, 0x00ce, &Interpreter::lsn},
{0x0086, 0x00ce, &Interpreter::sln},
{0x0088, 0x00ce, &Interpreter::lsm},
{0x008a, 0x00ce, &Interpreter::slm},
{0x008c, 0x00ce, &Interpreter::lsnm},
{0x008e, 0x00ce, &Interpreter::slnm},
{0x00c3, 0x00cf, Ext::ldax},
{0x00c7, 0x00cf, Ext::ldaxn},
{0x00cb, 0x00cf, Ext::ldaxm},
{0x00cf, 0x00cf, Ext::ldaxnm},
{0x00c3, 0x00cf, &Interpreter::ldax},
{0x00c7, 0x00cf, &Interpreter::ldaxn},
{0x00cb, 0x00cf, &Interpreter::ldaxm},
{0x00cf, 0x00cf, &Interpreter::ldaxnm},
{0x00c0, 0x00cc, Ext::ld},
{0x00c4, 0x00cc, Ext::ldn},
{0x00c8, 0x00cc, Ext::ldm},
{0x00cc, 0x00cc, Ext::ldnm},
{0x00c0, 0x00cc, &Interpreter::ld},
{0x00c4, 0x00cc, &Interpreter::ldn},
{0x00c8, 0x00cc, &Interpreter::ldm},
{0x00cc, 0x00cc, &Interpreter::ldnm},
}};
// clang-format on
@@ -266,7 +265,7 @@ void InitInstructionTables()
// ext op table
for (size_t i = 0; i < s_ext_op_table.size(); i++)
{
s_ext_op_table[i] = nop;
s_ext_op_table[i] = &Interpreter::nop;
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes_ext);
if (iter == s_opcodes_ext.cend())
@@ -278,7 +277,7 @@ void InitInstructionTables()
// op table
for (size_t i = 0; i < s_op_table.size(); i++)
{
s_op_table[i] = nop;
s_op_table[i] = &Interpreter::nop;
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes);
if (iter == s_opcodes.cend())
@@ -8,7 +8,9 @@
namespace DSP::Interpreter
{
using InterpreterFunction = void (*)(UDSPInstruction);
class Interpreter;
using InterpreterFunction = void (Interpreter::*)(UDSPInstruction);
InterpreterFunction GetOp(UDSPInstruction inst);
InterpreterFunction GetExtOp(UDSPInstruction inst);
+3 -352
View File
@@ -5,376 +5,27 @@
#pragma once
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPStacks.h"
namespace DSP::Interpreter
{
// ---------------------------------------------------------------------------------------
// --- SR
// ---------------------------------------------------------------------------------------
static inline void dsp_SR_set_flag(int flag)
{
g_dsp.r.sr |= flag;
}
static inline bool dsp_SR_is_flag_set(int flag)
{
return (g_dsp.r.sr & flag) != 0;
}
// ---------------------------------------------------------------------------------------
// --- AR increments, decrements
// ---------------------------------------------------------------------------------------
static inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix)
{
u32 ar = g_dsp.r.ar[reg];
u32 wr = g_dsp.r.wr[reg];
s32 ix = _ix;
u32 mx = (wr | 1) << 1;
u32 nar = ar + ix;
u32 dar = (nar ^ ar ^ ix) & mx;
if (ix >= 0)
{
if (dar > wr) // overflow
nar -= wr + 1;
}
else
{
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
nar += wr + 1;
}
return nar;
}
static inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix)
{
u32 ar = g_dsp.r.ar[reg];
u32 wr = g_dsp.r.wr[reg];
s32 ix = _ix;
u32 mx = (wr | 1) << 1;
u32 nar = ar - ix;
u32 dar = (nar ^ ar ^ ~ix) & mx;
if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000)
{
if (dar > wr) // overflow
nar -= wr + 1;
}
else
{
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
nar += wr + 1;
}
return nar;
}
static inline u16 dsp_increment_addr_reg(u16 reg)
{
u32 ar = g_dsp.r.ar[reg];
u32 wr = g_dsp.r.wr[reg];
u32 nar = ar + 1;
if ((nar ^ ar) > ((wr | 1) << 1))
nar -= wr + 1;
return nar;
}
static inline u16 dsp_decrement_addr_reg(u16 reg)
{
u32 ar = g_dsp.r.ar[reg];
u32 wr = g_dsp.r.wr[reg];
u32 nar = ar + wr;
if (((nar ^ ar) & ((wr | 1) << 1)) > wr)
nar -= wr + 1;
return nar;
}
// ---------------------------------------------------------------------------------------
// --- reg
// ---------------------------------------------------------------------------------------
static inline u16 dsp_op_read_reg(int _reg)
{
int reg = _reg & 0x1f;
switch (reg)
{
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
return dsp_reg_load_stack(static_cast<StackRegister>(reg - DSP_REG_ST0));
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
return g_dsp.r.ar[reg - DSP_REG_AR0];
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
return g_dsp.r.ix[reg - DSP_REG_IX0];
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
return g_dsp.r.wr[reg - DSP_REG_WR0];
case DSP_REG_ACH0:
case DSP_REG_ACH1:
return g_dsp.r.ac[reg - DSP_REG_ACH0].h;
case DSP_REG_CR:
return g_dsp.r.cr;
case DSP_REG_SR:
return g_dsp.r.sr;
case DSP_REG_PRODL:
return g_dsp.r.prod.l;
case DSP_REG_PRODM:
return g_dsp.r.prod.m;
case DSP_REG_PRODH:
return g_dsp.r.prod.h;
case DSP_REG_PRODM2:
return g_dsp.r.prod.m2;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
return g_dsp.r.ax[reg - DSP_REG_AXL0].l;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
return g_dsp.r.ax[reg - DSP_REG_AXH0].h;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
return g_dsp.r.ac[reg - DSP_REG_ACL0].l;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
return g_dsp.r.ac[reg - DSP_REG_ACM0].m;
default:
ASSERT_MSG(DSP_INT, 0, "cannot happen");
return 0;
}
}
static inline void dsp_op_write_reg(int _reg, u16 val)
{
int reg = _reg & 0x1f;
switch (reg)
{
// 8-bit sign extended registers. Should look at prod.h too...
case DSP_REG_ACH0:
case DSP_REG_ACH1:
// sign extend from the bottom 8 bits.
g_dsp.r.ac[reg - DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val;
break;
// Stack registers.
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
dsp_reg_store_stack(static_cast<StackRegister>(reg - DSP_REG_ST0), val);
break;
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
g_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:
g_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:
g_dsp.r.wr[reg - DSP_REG_WR0] = val;
break;
case DSP_REG_CR:
g_dsp.r.cr = val;
break;
case DSP_REG_SR:
g_dsp.r.sr = val;
break;
case DSP_REG_PRODL:
g_dsp.r.prod.l = val;
break;
case DSP_REG_PRODM:
g_dsp.r.prod.m = val;
break;
case DSP_REG_PRODH:
g_dsp.r.prod.h = val;
break;
case DSP_REG_PRODM2:
g_dsp.r.prod.m2 = val;
break;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
g_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
break;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
g_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
break;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
g_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
g_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
break;
}
}
static inline void dsp_conditional_extend_accum(int reg)
{
switch (reg)
{
case DSP_REG_ACM0:
case DSP_REG_ACM1:
if (g_dsp.r.sr & SR_40_MODE_BIT)
{
// Sign extend into whole accum.
u16 val = g_dsp.r.ac[reg - DSP_REG_ACM0].m;
g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000;
g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0;
}
}
}
// ---------------------------------------------------------------------------------------
// --- prod (40-bit)
// ---------------------------------------------------------------------------------------
static inline s64 dsp_get_long_prod()
{
s64 val = (s8)(u8)g_dsp.r.prod.h;
val <<= 32;
s64 low_prod = g_dsp.r.prod.m;
low_prod += g_dsp.r.prod.m2;
low_prod <<= 16;
low_prod |= g_dsp.r.prod.l;
val += low_prod;
return val;
}
static inline s64 dsp_get_long_prod_round_prodl()
{
s64 prod = dsp_get_long_prod();
if (prod & 0x10000)
prod = (prod + 0x8000) & ~0xffff;
else
prod = (prod + 0x7fff) & ~0xffff;
return prod;
}
// For accurate emulation, this is wrong - but the real prod registers behave
// in completely bizarre ways. Not needed to emulate them correctly for game ucodes.
inline void dsp_set_long_prod(s64 val)
{
g_dsp.r.prod.val = val & 0x000000FFFFFFFFFFULL;
}
// ---------------------------------------------------------------------------------------
// --- ACC - main accumulators (40-bit)
// ---------------------------------------------------------------------------------------
inline s64 dsp_get_long_acc(int reg)
{
return ((s64)(g_dsp.r.ac[reg].val << 24) >> 24);
}
inline void dsp_set_long_acc(int _reg, s64 val)
{
g_dsp.r.ac[_reg].val = (u64)val;
}
inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40
// s64 -> s40
inline s64 dsp_convert_long_acc(s64 val)
{
return ((val << 24) >> 24);
}
inline s64 dsp_round_long_acc(s64 val)
{
if (val & 0x10000)
if ((val & 0x10000) != 0)
val = (val + 0x8000) & ~0xffff;
else
val = (val + 0x7fff) & ~0xffff;
return val;
}
inline s16 dsp_get_acc_l(int _reg)
{
return (s16)g_dsp.r.ac[_reg].l;
}
inline s16 dsp_get_acc_m(int _reg)
{
return (s16)g_dsp.r.ac[_reg].m;
}
inline s16 dsp_get_acc_h(int _reg)
{
return (s16)g_dsp.r.ac[_reg].h;
}
inline u16 dsp_op_read_reg_and_saturate(u8 _reg)
{
if (g_dsp.r.sr & SR_40_MODE_BIT)
{
s64 acc = dsp_get_long_acc(_reg);
if (acc != (s32)acc)
{
if (acc > 0)
return 0x7fff;
else
return 0x8000;
}
else
{
return g_dsp.r.ac[_reg].m;
}
}
else
{
return g_dsp.r.ac[_reg].m;
}
}
// ---------------------------------------------------------------------------------------
// --- AX - extra accumulators (32-bit)
// ---------------------------------------------------------------------------------------
inline s32 dsp_get_long_acx(int _reg)
{
return (s32)(((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l);
}
inline s16 dsp_get_ax_l(int _reg)
{
return (s16)g_dsp.r.ax[_reg].l;
}
inline s16 dsp_get_ax_h(int _reg)
{
return (s16)g_dsp.r.ax[_reg].h;
}
} // namespace DSP::Interpreter
@@ -5,115 +5,68 @@
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntTables.h"
namespace DSP::Interpreter
{
namespace
Interpreter::Interpreter(DSPCore& dsp) : m_dsp_core{dsp}
{
void ExecuteInstruction(const UDSPInstruction inst)
InitInstructionTables();
}
Interpreter::~Interpreter() = default;
void Interpreter::ExecuteInstruction(const UDSPInstruction inst)
{
const DSPOPCTemplate* opcode_template = GetOpTemplate(inst);
if (opcode_template->extended)
{
GetExtOp(inst)(inst);
(this->*GetExtOp(inst))(inst);
}
GetOp(inst)(inst);
(this->*GetOp(inst))(inst);
if (opcode_template->extended)
{
ApplyWriteBackLog();
}
}
} // Anonymous namespace
// NOTE: These have nothing to do with g_dsp.r.cr !
void WriteCR(u16 val)
void Interpreter::Step()
{
// reset
if (val & 1)
{
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL RESET");
DSPCore_Reset();
val &= ~1;
}
// init
else if (val == 4)
{
// HAX!
// OSInitAudioSystem ucode should send this mail - not DSP core itself
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT");
g_init_hax = true;
val |= 0x800;
}
m_dsp_core.CheckExceptions();
m_dsp_core.DSPState().step_counter++;
// update cr
g_dsp.cr = val;
}
const u16 opc = m_dsp_core.DSPState().FetchInstruction();
ExecuteInstruction(UDSPInstruction{opc});
u16 ReadCR()
{
if (g_dsp.pc & 0x8000)
{
g_dsp.cr |= 0x800;
}
else
{
g_dsp.cr &= ~0x800;
}
return g_dsp.cr;
}
void Step()
{
DSPCore_CheckExceptions();
g_dsp.step_counter++;
#if PROFILE
g_dsp.err_pc = g_dsp.pc;
ProfilerAddDelta(g_dsp.err_pc, 1);
if (g_dsp.step_counter == 1)
{
ProfilerInit();
}
if ((g_dsp.step_counter & 0xFFFFF) == 0)
{
ProfilerDump(g_dsp.step_counter);
}
#endif
u16 opc = dsp_fetch_code();
ExecuteInstruction(UDSPInstruction(opc));
if (Analyzer::GetCodeFlags(static_cast<u16>(g_dsp.pc - 1u)) & Analyzer::CODE_LOOP_END)
const auto pc = m_dsp_core.DSPState().pc;
if ((Analyzer::GetCodeFlags(static_cast<u16>(pc - 1)) & Analyzer::CODE_LOOP_END) != 0)
HandleLoop();
}
// Used by thread mode.
int RunCyclesThread(int cycles)
int Interpreter::RunCyclesThread(int cycles)
{
auto& state = m_dsp_core.DSPState();
while (true)
{
if (g_dsp.cr & CR_HALT)
if ((state.cr & CR_HALT) != 0)
return 0;
if (g_dsp.external_interrupt_waiting)
if (state.external_interrupt_waiting)
{
DSPCore_CheckExternalInterrupt();
DSPCore_SetExternalInterrupt(false);
m_dsp_core.CheckExternalInterrupt();
m_dsp_core.SetExternalInterrupt(false);
}
Step();
@@ -124,16 +77,19 @@ int RunCyclesThread(int cycles)
}
// This one has basic idle skipping, and checks breakpoints.
int RunCyclesDebug(int cycles)
int Interpreter::RunCyclesDebug(int cycles)
{
auto& state = m_dsp_core.DSPState();
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
for (int i = 0; i < 8; i++)
{
if (g_dsp.cr & CR_HALT)
if ((state.cr & CR_HALT) != 0)
return 0;
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
{
DSPCore_SetState(State::Stepping);
m_dsp_core.SetState(State::Stepping);
return cycles;
}
Step();
@@ -148,16 +104,19 @@ int RunCyclesDebug(int cycles)
// idle loops.
for (int i = 0; i < 8; i++)
{
if (g_dsp.cr & CR_HALT)
if ((state.cr & CR_HALT) != 0)
return 0;
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
{
DSPCore_SetState(State::Stepping);
m_dsp_core.SetState(State::Stepping);
return cycles;
}
// Idle skipping.
if (Analyzer::GetCodeFlags(g_dsp.pc) & Analyzer::CODE_IDLE_SKIP)
if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
return 0;
Step();
cycles--;
if (cycles < 0)
@@ -167,9 +126,9 @@ int RunCyclesDebug(int cycles)
// Now, lets run some more without idle skipping.
for (int i = 0; i < 200; i++)
{
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
{
DSPCore_SetState(State::Stepping);
m_dsp_core.SetState(State::Stepping);
return cycles;
}
Step();
@@ -183,16 +142,20 @@ int RunCyclesDebug(int cycles)
}
// Used by non-thread mode. Meant to be efficient.
int RunCycles(int cycles)
int Interpreter::RunCycles(int cycles)
{
auto& state = m_dsp_core.DSPState();
// First, let's run a few cycles with no idle skipping so that things can
// progress a bit.
for (int i = 0; i < 8; i++)
{
if (g_dsp.cr & CR_HALT)
if ((state.cr & CR_HALT) != 0)
return 0;
Step();
cycles--;
if (cycles < 0)
return 0;
}
@@ -203,13 +166,16 @@ int RunCycles(int cycles)
// idle loops.
for (int i = 0; i < 8; i++)
{
if (g_dsp.cr & CR_HALT)
if ((state.cr & CR_HALT) != 0)
return 0;
// Idle skipping.
if (Analyzer::GetCodeFlags(g_dsp.pc) & Analyzer::CODE_IDLE_SKIP)
if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
return 0;
Step();
cycles--;
if (cycles < 0)
return 0;
}
@@ -227,7 +193,656 @@ int RunCycles(int cycles)
}
}
void nop(const UDSPInstruction opc)
// NOTE: These have nothing to do with SDSP::r::cr!
void Interpreter::WriteCR(u16 val)
{
// reset
if ((val & 1) != 0)
{
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL RESET");
m_dsp_core.Reset();
val &= ~1;
}
// init
else if (val == 4)
{
// HAX!
// OSInitAudioSystem ucode should send this mail - not DSP core itself
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT");
m_dsp_core.SetInitHax(true);
val |= 0x800;
}
// update cr
m_dsp_core.DSPState().cr = val;
}
u16 Interpreter::ReadCR()
{
auto& state = m_dsp_core.DSPState();
if ((state.pc & 0x8000) != 0)
{
state.cr |= 0x800;
}
else
{
state.cr &= ~0x800;
}
return state.cr;
}
void Interpreter::SetSRFlag(u16 flag)
{
m_dsp_core.DSPState().SetSRFlag(flag);
}
bool Interpreter::IsSRFlagSet(u16 flag) const
{
return m_dsp_core.DSPState().IsSRFlagSet(flag);
}
bool Interpreter::CheckCondition(u8 condition) const
{
const auto IsCarry = [this] { return IsSRFlagSet(SR_CARRY); };
const auto IsOverflow = [this] { return IsSRFlagSet(SR_OVERFLOW); };
const auto IsOverS32 = [this] { return IsSRFlagSet(SR_OVER_S32); };
const auto IsLess = [this] {
const auto& state = m_dsp_core.DSPState();
return (state.r.sr & SR_OVERFLOW) != (state.r.sr & SR_SIGN);
};
const auto IsZero = [this] { return IsSRFlagSet(SR_ARITH_ZERO); };
const auto IsLogicZero = [this] { return IsSRFlagSet(SR_LOGIC_ZERO); };
const auto IsConditionA = [this] {
return (IsSRFlagSet(SR_OVER_S32) || IsSRFlagSet(SR_TOP2BITS)) && !IsSRFlagSet(SR_ARITH_ZERO);
};
switch (condition & 0xf)
{
case 0xf: // Always true.
return true;
case 0x0: // GE - Greater Equal
return !IsLess();
case 0x1: // L - Less
return IsLess();
case 0x2: // G - Greater
return !IsLess() && !IsZero();
case 0x3: // LE - Less Equal
return IsLess() || IsZero();
case 0x4: // NZ - Not Zero
return !IsZero();
case 0x5: // Z - Zero
return IsZero();
case 0x6: // NC - Not carry
return !IsCarry();
case 0x7: // C - Carry
return IsCarry();
case 0x8: // ? - Not over s32
return !IsOverS32();
case 0x9: // ? - Over s32
return IsOverS32();
case 0xa: // ?
return IsConditionA();
case 0xb: // ?
return !IsConditionA();
case 0xc: // LNZ - Logic Not Zero
return !IsLogicZero();
case 0xd: // LZ - Logic Zero
return IsLogicZero();
case 0xe: // 0 - Overflow
return IsOverflow();
default:
return true;
}
}
u16 Interpreter::IncrementAddressRegister(u16 reg) const
{
auto& state = m_dsp_core.DSPState();
const u32 ar = state.r.ar[reg];
const u32 wr = state.r.wr[reg];
u32 nar = ar + 1;
if ((nar ^ ar) > ((wr | 1) << 1))
nar -= wr + 1;
return static_cast<u16>(nar);
}
u16 Interpreter::DecrementAddressRegister(u16 reg) const
{
const auto& state = m_dsp_core.DSPState();
const u32 ar = state.r.ar[reg];
const u32 wr = state.r.wr[reg];
u32 nar = ar + wr;
if (((nar ^ ar) & ((wr | 1) << 1)) > wr)
nar -= wr + 1;
return static_cast<u16>(nar);
}
u16 Interpreter::IncreaseAddressRegister(u16 reg, s16 ix_) const
{
const auto& state = m_dsp_core.DSPState();
const u32 ar = state.r.ar[reg];
const u32 wr = state.r.wr[reg];
const s32 ix = ix_;
const u32 mx = (wr | 1) << 1;
u32 nar = ar + ix;
const u32 dar = (nar ^ ar ^ ix) & mx;
if (ix >= 0)
{
if (dar > wr) // Overflow
nar -= wr + 1;
}
else
{
// Underflow or below min for mask
if ((((nar + wr + 1) ^ nar) & dar) <= wr)
nar += wr + 1;
}
return static_cast<u16>(nar);
}
u16 Interpreter::DecreaseAddressRegister(u16 reg, s16 ix_) const
{
const auto& state = m_dsp_core.DSPState();
const u32 ar = state.r.ar[reg];
const u32 wr = state.r.wr[reg];
const s32 ix = ix_;
const u32 mx = (wr | 1) << 1;
u32 nar = ar - ix;
const u32 dar = (nar ^ ar ^ ~ix) & mx;
// (ix < 0 && ix != -0x8000)
if (static_cast<u32>(ix) > 0xFFFF8000)
{
if (dar > wr) // overflow
nar -= wr + 1;
}
else
{
// Underflow or below min for mask
if ((((nar + wr + 1) ^ nar) & dar) <= wr)
nar += wr + 1;
}
return static_cast<u16>(nar);
}
s32 Interpreter::GetLongACX(s32 reg) const
{
const auto& state = m_dsp_core.DSPState();
return static_cast<s32>((static_cast<u32>(state.r.ax[reg].h) << 16) | state.r.ax[reg].l);
}
s16 Interpreter::GetAXLow(s32 reg) const
{
return static_cast<s16>(m_dsp_core.DSPState().r.ax[reg].l);
}
s16 Interpreter::GetAXHigh(s32 reg) const
{
return static_cast<s16>(m_dsp_core.DSPState().r.ax[reg].h);
}
s64 Interpreter::GetLongAcc(s32 reg) const
{
const auto& state = m_dsp_core.DSPState();
return static_cast<s64>(state.r.ac[reg].val << 24) >> 24;
}
void Interpreter::SetLongAcc(s32 reg, s64 value)
{
auto& state = m_dsp_core.DSPState();
state.r.ac[reg].val = static_cast<u64>(value);
}
s16 Interpreter::GetAccLow(s32 reg) const
{
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].l);
}
s16 Interpreter::GetAccMid(s32 reg) const
{
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].m);
}
s16 Interpreter::GetAccHigh(s32 reg) const
{
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].h);
}
s64 Interpreter::GetLongProduct() const
{
const auto& state = m_dsp_core.DSPState();
s64 val = static_cast<s8>(static_cast<u8>(state.r.prod.h));
val <<= 32;
s64 low_prod = state.r.prod.m;
low_prod += state.r.prod.m2;
low_prod <<= 16;
low_prod |= state.r.prod.l;
val += low_prod;
return val;
}
s64 Interpreter::GetLongProductRounded() const
{
const s64 prod = GetLongProduct();
if ((prod & 0x10000) != 0)
return (prod + 0x8000) & ~0xffff;
else
return (prod + 0x7fff) & ~0xffff;
}
void Interpreter::SetLongProduct(s64 value)
{
// For accurate emulation, this is wrong - but the real prod registers behave
// in completely bizarre ways. Not needed to emulate them correctly for game ucodes.
m_dsp_core.DSPState().r.prod.val = static_cast<u64>(value & 0x000000FFFFFFFFFFULL);
}
s64 Interpreter::GetMultiplyProduct(u16 a, u16 b, u8 sign) const
{
s64 prod;
// Unsigned
if (sign == 1 && IsSRFlagSet(SR_MUL_UNSIGNED))
prod = static_cast<u32>(a * b);
else if (sign == 2 && IsSRFlagSet(SR_MUL_UNSIGNED)) // mixed
prod = a * static_cast<s16>(b);
else // Signed
prod = static_cast<s16>(a) * static_cast<s16>(b);
// Conditionally multiply by 2.
if (!IsSRFlagSet(SR_MUL_MODIFY))
prod <<= 1;
return prod;
}
s64 Interpreter::Multiply(u16 a, u16 b, u8 sign) const
{
return GetMultiplyProduct(a, b, sign);
}
s64 Interpreter::MultiplyAdd(u16 a, u16 b, u8 sign) const
{
return GetLongProduct() + GetMultiplyProduct(a, b, sign);
}
s64 Interpreter::MultiplySub(u16 a, u16 b, u8 sign) const
{
return GetLongProduct() - GetMultiplyProduct(a, b, sign);
}
s64 Interpreter::MultiplyMulX(u8 axh0, u8 axh1, u16 val1, u16 val2) const
{
s64 result;
if (axh0 == 0 && axh1 == 0)
result = Multiply(val1, val2, 1); // Unsigned support ON if both ax?.l regs are used
else if (axh0 == 0 && axh1 == 1)
result = Multiply(val1, val2, 2); // Mixed support ON (u16)axl.0 * (s16)axh.1
else if (axh0 == 1 && axh1 == 0)
result = Multiply(val2, val1, 2); // Mixed support ON (u16)axl.1 * (s16)axh.0
else
result = Multiply(val1, val2, 0); // Unsigned support OFF if both ax?.h regs are used
return result;
}
void Interpreter::UpdateSR16(s16 value, bool carry, bool overflow, bool over_s32)
{
auto& state = m_dsp_core.DSPState();
state.r.sr &= ~SR_CMP_MASK;
// 0x01
if (carry)
{
state.r.sr |= SR_CARRY;
}
// 0x02 and 0x80
if (overflow)
{
state.r.sr |= SR_OVERFLOW;
state.r.sr |= SR_OVERFLOW_STICKY;
}
// 0x04
if (value == 0)
{
state.r.sr |= SR_ARITH_ZERO;
}
// 0x08
if (value < 0)
{
state.r.sr |= SR_SIGN;
}
// 0x10
if (over_s32)
{
state.r.sr |= SR_OVER_S32;
}
// 0x20 - Checks if top bits of m are equal
if (((static_cast<u16>(value) >> 14) == 0) || ((static_cast<u16>(value) >> 14) == 3))
{
state.r.sr |= SR_TOP2BITS;
}
}
void Interpreter::UpdateSR64(s64 value, bool carry, bool overflow)
{
auto& state = m_dsp_core.DSPState();
state.r.sr &= ~SR_CMP_MASK;
// 0x01
if (carry)
{
state.r.sr |= SR_CARRY;
}
// 0x02 and 0x80
if (overflow)
{
state.r.sr |= SR_OVERFLOW;
state.r.sr |= SR_OVERFLOW_STICKY;
}
// 0x04
if (value == 0)
{
state.r.sr |= SR_ARITH_ZERO;
}
// 0x08
if (value < 0)
{
state.r.sr |= SR_SIGN;
}
// 0x10
if (value != static_cast<s32>(value))
{
state.r.sr |= SR_OVER_S32;
}
// 0x20 - Checks if top bits of m are equal
if (((value & 0xc0000000) == 0) || ((value & 0xc0000000) == 0xc0000000))
{
state.r.sr |= SR_TOP2BITS;
}
}
void Interpreter::UpdateSRLogicZero(bool value)
{
auto& state = m_dsp_core.DSPState();
if (value)
state.r.sr |= SR_LOGIC_ZERO;
else
state.r.sr &= ~SR_LOGIC_ZERO;
}
u16 Interpreter::OpReadRegister(int reg_)
{
const int reg = reg_ & 0x1f;
auto& state = m_dsp_core.DSPState();
switch (reg)
{
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
return state.PopStack(static_cast<StackRegister>(reg - DSP_REG_ST0));
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
return state.r.ar[reg - DSP_REG_AR0];
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
return state.r.ix[reg - DSP_REG_IX0];
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
return state.r.wr[reg - DSP_REG_WR0];
case DSP_REG_ACH0:
case DSP_REG_ACH1:
return state.r.ac[reg - DSP_REG_ACH0].h;
case DSP_REG_CR:
return state.r.cr;
case DSP_REG_SR:
return state.r.sr;
case DSP_REG_PRODL:
return state.r.prod.l;
case DSP_REG_PRODM:
return state.r.prod.m;
case DSP_REG_PRODH:
return state.r.prod.h;
case DSP_REG_PRODM2:
return state.r.prod.m2;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
return state.r.ax[reg - DSP_REG_AXL0].l;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
return state.r.ax[reg - DSP_REG_AXH0].h;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
return state.r.ac[reg - DSP_REG_ACL0].l;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
return state.r.ac[reg - DSP_REG_ACM0].m;
default:
ASSERT_MSG(DSP_INT, 0, "cannot happen");
return 0;
}
}
u16 Interpreter::OpReadRegisterAndSaturate(int reg) const
{
if (IsSRFlagSet(SR_40_MODE_BIT))
{
const s64 acc = GetLongAcc(reg);
if (acc != static_cast<s32>(acc))
{
if (acc > 0)
return 0x7fff;
else
return 0x8000;
}
return m_dsp_core.DSPState().r.ac[reg].m;
}
return m_dsp_core.DSPState().r.ac[reg].m;
}
void Interpreter::OpWriteRegister(int reg_, u16 val)
{
const int reg = reg_ & 0x1f;
auto& state = m_dsp_core.DSPState();
switch (reg)
{
// 8-bit sign extended registers. Should look at prod.h too...
case DSP_REG_ACH0:
case DSP_REG_ACH1:
// sign extend from the bottom 8 bits.
state.r.ac[reg - DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val;
break;
// Stack registers.
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
state.StoreStack(static_cast<StackRegister>(reg - DSP_REG_ST0), val);
break;
case DSP_REG_AR0:
case DSP_REG_AR1:
case DSP_REG_AR2:
case DSP_REG_AR3:
state.r.ar[reg - DSP_REG_AR0] = val;
break;
case DSP_REG_IX0:
case DSP_REG_IX1:
case DSP_REG_IX2:
case DSP_REG_IX3:
state.r.ix[reg - DSP_REG_IX0] = val;
break;
case DSP_REG_WR0:
case DSP_REG_WR1:
case DSP_REG_WR2:
case DSP_REG_WR3:
state.r.wr[reg - DSP_REG_WR0] = val;
break;
case DSP_REG_CR:
state.r.cr = val;
break;
case DSP_REG_SR:
state.r.sr = val;
break;
case DSP_REG_PRODL:
state.r.prod.l = val;
break;
case DSP_REG_PRODM:
state.r.prod.m = val;
break;
case DSP_REG_PRODH:
state.r.prod.h = val;
break;
case DSP_REG_PRODM2:
state.r.prod.m2 = val;
break;
case DSP_REG_AXL0:
case DSP_REG_AXL1:
state.r.ax[reg - DSP_REG_AXL0].l = val;
break;
case DSP_REG_AXH0:
case DSP_REG_AXH1:
state.r.ax[reg - DSP_REG_AXH0].h = val;
break;
case DSP_REG_ACL0:
case DSP_REG_ACL1:
state.r.ac[reg - DSP_REG_ACL0].l = val;
break;
case DSP_REG_ACM0:
case DSP_REG_ACM1:
state.r.ac[reg - DSP_REG_ACM0].m = val;
break;
}
}
void Interpreter::ConditionalExtendAccum(int reg)
{
if (reg != DSP_REG_ACM0 && reg != DSP_REG_ACM1)
return;
if (!IsSRFlagSet(SR_40_MODE_BIT))
return;
// Sign extend into whole accum.
auto& state = m_dsp_core.DSPState();
const u16 val = state.r.ac[reg - DSP_REG_ACM0].m;
state.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) != 0 ? 0xFFFF : 0x0000;
state.r.ac[reg - DSP_REG_ACM0].l = 0;
}
// The ext op are writing their output into the backlog which is
// being applied to the real registers after the main op was executed
void Interpreter::ApplyWriteBackLog()
{
// Always make sure to have an extra entry at the end w/ -1 to avoid
// infinitive loops
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
{
u16 value = m_write_back_log[i];
#ifdef PRECISE_BACKLOG
value |= OpReadRegister(m_write_back_log_idx[i]);
#endif
OpWriteRegister(m_write_back_log_idx[i], value);
// Clear back log
m_write_back_log_idx[i] = -1;
}
}
void Interpreter::WriteToBackLog(int i, int idx, u16 value)
{
m_write_back_log[i] = value;
m_write_back_log_idx[i] = idx;
}
// This function is being called in the main op after all input regs were read
// and before it writes into any regs. This way we can always use bitwise or to
// apply the ext command output, because if the main op didn't change the value
// then 0 | ext output = ext output and if it did then bitwise or is still the
// right thing to do
// Only needed for cases when mainop and extended are modifying the same ACC
// Games are not doing that + in motorola (similar DSP) dox this is forbidden to do.
void Interpreter::ZeroWriteBackLog()
{
#ifdef PRECISE_BACKLOG
// always make sure to have an extra entry at the end w/ -1 to avoid
// infinitive loops
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
{
OpWriteRegister(m_write_back_log_idx[i], 0);
}
#endif
}
void Interpreter::ZeroWriteBackLogPreserveAcc([[maybe_unused]] u8 acc)
{
#ifdef PRECISE_BACKLOG
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
{
// acc0
if (acc == 0 &&
((m_write_back_log_idx[i] == DSP_REG_ACL0) || (m_write_back_log_idx[i] == DSP_REG_ACM0) ||
(m_write_back_log_idx[i] == DSP_REG_ACH0)))
{
continue;
}
// acc1
if (acc == 1 &&
((m_write_back_log_idx[i] == DSP_REG_ACL1) || (m_write_back_log_idx[i] == DSP_REG_ACM1) ||
(m_write_back_log_idx[i] == DSP_REG_ACH1)))
{
continue;
}
OpWriteRegister(m_write_back_log_idx[i], 0);
}
#endif
}
void Interpreter::nop(const UDSPInstruction opc)
{
// The real nop is 0. Anything else is bad.
if (opc == 0)
+235 -131
View File
@@ -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();
class Interpreter
{
public:
explicit Interpreter(DSPCore& dsp);
~Interpreter();
// See: DspIntBranch.cpp
void HandleLoop();
Interpreter(const Interpreter&) = delete;
Interpreter& operator=(const Interpreter&) = delete;
// 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);
Interpreter(Interpreter&&) = delete;
Interpreter& operator=(Interpreter&&) = delete;
void WriteCR(u16 val);
u16 ReadCR();
void Step();
// 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);
// 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