mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
Merge pull request #10692 from Pokechu22/dsp-manual-set40-and-write-backlog
docs/DSP: Add sections on 16-bit and 40-bit modes and on main and extended opcode writing to the same register
This commit is contained in:
@ -45,7 +45,7 @@ void Interpreter::clrl(const UDSPInstruction opc)
|
||||
//----
|
||||
|
||||
// ANDCF $acD.m, #I
|
||||
// 0000 001r 1100 0000
|
||||
// 0000 001d 1100 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Set logic zero (LZ) flag in status register $sr if result of logic AND of
|
||||
// accumulator mid part $acD.m with immediate value I is equal to I.
|
||||
@ -61,7 +61,7 @@ void Interpreter::andcf(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ANDF $acD.m, #I
|
||||
// 0000 001r 1010 0000
|
||||
// 0000 001d 1010 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Set logic zero (LZ) flag in status register $sr if result of logical AND
|
||||
// operation of accumulator mid part $acD.m with immediate value I is equal
|
||||
@ -81,7 +81,7 @@ void Interpreter::andf(const UDSPInstruction opc)
|
||||
|
||||
// TST
|
||||
// 1011 r001 xxxx xxxx
|
||||
// Test accumulator %acR.
|
||||
// Test accumulator $acR.
|
||||
//
|
||||
// flags out: --xx xx00
|
||||
void Interpreter::tst(const UDSPInstruction opc)
|
||||
@ -143,11 +143,12 @@ void Interpreter::cmpaxh(const UDSPInstruction opc)
|
||||
ZeroWriteBackLog();
|
||||
}
|
||||
|
||||
// CMPI $amD, #I
|
||||
// 0000 001r 1000 0000
|
||||
// CMPI $acD, #I
|
||||
// 0000 001d 1000 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
|
||||
// Although flags are being set regarding whole accumulator register.
|
||||
// Compares accumulator with immediate. Comparison is executed
|
||||
// by subtracting the immediate (16-bit sign extended) from mid accumulator
|
||||
// $acD.hm and computing flags based on whole accumulator $acD.
|
||||
//
|
||||
// flags out: x-xx xxxx
|
||||
void Interpreter::cmpi(const UDSPInstruction opc)
|
||||
@ -166,8 +167,8 @@ void Interpreter::cmpi(const UDSPInstruction opc)
|
||||
|
||||
// CMPIS $acD, #I
|
||||
// 0000 011d iiii iiii
|
||||
// Compares accumulator with short immediate. Comaprison is executed
|
||||
// by subtracting short immediate (8bit sign extended) from mid accumulator
|
||||
// Compares accumulator with short immediate. Comparison is executed
|
||||
// by subtracting the short immediate (8-bit sign extended) from mid accumulator
|
||||
// $acD.hm and computing flags based on whole accumulator $acD.
|
||||
//
|
||||
// flags out: x-xx xxxx
|
||||
@ -320,7 +321,7 @@ void Interpreter::notc(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// XORI $acD.m, #I
|
||||
// 0000 001r 0010 0000
|
||||
// 0000 001d 0010 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic exclusive or (XOR) of accumulator mid part $acD.m with
|
||||
// immediate value I.
|
||||
@ -337,7 +338,7 @@ void Interpreter::xori(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ANDI $acD.m, #I
|
||||
// 0000 001r 0100 0000
|
||||
// 0000 001d 0100 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic AND of accumulator mid part $acD.m with immediate value I.
|
||||
//
|
||||
@ -354,7 +355,7 @@ void Interpreter::andi(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ORI $acD.m, #I
|
||||
// 0000 001r 0110 0000
|
||||
// 0000 001d 0110 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic OR of accumulator mid part $acD.m with immediate value I.
|
||||
//
|
||||
@ -489,8 +490,8 @@ void Interpreter::addaxl(const UDSPInstruction opc)
|
||||
UpdateSR64Add(acc, acx, GetLongAcc(dreg));
|
||||
}
|
||||
|
||||
// ADDI $amR, #I
|
||||
// 0000 001r 0000 0000
|
||||
// ADDI $acD, #I
|
||||
// 0000 001d 0000 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
|
||||
//
|
||||
|
@ -16,8 +16,23 @@
|
||||
|
||||
namespace DSP::Interpreter
|
||||
{
|
||||
// Not needed for game ucodes (it slows down interpreter + easier to compare int VS
|
||||
// dspjit64 without it)
|
||||
// Correctly handle instructions such as `INC'L $ac0 : $ac0.l, @$ar0` (encoded as 0x7660) where both
|
||||
// the main opcode and the extension opcode modify the same register. See the "Extended opcodes"
|
||||
// section in the manual for more details. No official uCode writes to the same register twice like
|
||||
// this, so we don't emulate it by default (and also don't support it in the recompiler).
|
||||
//
|
||||
// Dolphin only supports this behavior in the interpreter when PRECISE_BACKLOG is defined.
|
||||
// In ExecuteInstruction, if an extended opcode is in use, the extended opcode's behavior is
|
||||
// executed first, followed by the main opcode's behavior. The extended opcode does not directly
|
||||
// write to registers, but instead records the writes into a backlog (WriteToBackLog). The main
|
||||
// opcode calls ZeroWriteBackLog after it is done reading the register values; this directly
|
||||
// writes zero to all registers that have pending writes in the backlog. The main opcode then is
|
||||
// free to write directly to registers it changes. Afterwards, ApplyWriteBackLog bitwise-ors the
|
||||
// value of the register and the value in the backlog; if the main opcode didn't write to the
|
||||
// register then ZeroWriteBackLog means that the pending value is being or'd with zero, so it's
|
||||
// used without changes. When PRECISE_BACKLOG is not defined, ZeroWriteBackLog does nothing and
|
||||
// ApplyWriteBackLog overwrites the register value with the value from the backlog (so writes from
|
||||
// extended opcodes "win" over the main opcode).
|
||||
//#define PRECISE_BACKLOG
|
||||
|
||||
Interpreter::Interpreter(DSPCore& dsp) : m_dsp_core{dsp}
|
||||
@ -809,7 +824,7 @@ void Interpreter::ConditionalExtendAccum(int reg)
|
||||
void Interpreter::ApplyWriteBackLog()
|
||||
{
|
||||
// Always make sure to have an extra entry at the end w/ -1 to avoid
|
||||
// infinitive loops
|
||||
// infinite loops
|
||||
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
|
||||
{
|
||||
u16 value = m_write_back_log[i];
|
||||
@ -823,6 +838,11 @@ void Interpreter::ApplyWriteBackLog()
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Interpreter::WriteToBackLog(int i, int idx, u16 value)
|
||||
{
|
||||
m_write_back_log[i] = value;
|
||||
@ -840,7 +860,7 @@ void Interpreter::ZeroWriteBackLog()
|
||||
{
|
||||
#ifdef PRECISE_BACKLOG
|
||||
// always make sure to have an extra entry at the end w/ -1 to avoid
|
||||
// infinitive loops
|
||||
// infinite loops
|
||||
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
|
||||
{
|
||||
OpWriteRegister(m_write_back_log_idx[i], 0);
|
||||
|
@ -235,11 +235,6 @@ private:
|
||||
|
||||
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);
|
||||
|
@ -53,7 +53,7 @@ void DSPEmitter::clrl(const UDSPInstruction opc)
|
||||
//----
|
||||
|
||||
// ANDCF $acD.m, #I
|
||||
// 0000 001r 1100 0000
|
||||
// 0000 001d 1100 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Set logic zero (LZ) flag in status register $sr if result of logic AND of
|
||||
// accumulator mid part $acD.m with immediate value I is equal to I.
|
||||
@ -88,7 +88,7 @@ void DSPEmitter::andcf(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ANDF $acD.m, #I
|
||||
// 0000 001r 1010 0000
|
||||
// 0000 001d 1010 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Set logic zero (LZ) flag in status register $sr if result of logical AND
|
||||
// operation of accumulator mid part $acD.m with immediate value I is equal
|
||||
@ -126,7 +126,7 @@ void DSPEmitter::andf(const UDSPInstruction opc)
|
||||
|
||||
// TST
|
||||
// 1011 r001 xxxx xxxx
|
||||
// Test accumulator %acR.
|
||||
// Test accumulator $acR.
|
||||
//
|
||||
// flags out: --xx xx00
|
||||
void DSPEmitter::tst(const UDSPInstruction opc)
|
||||
@ -220,11 +220,12 @@ void DSPEmitter::cmpaxh(const UDSPInstruction opc)
|
||||
}
|
||||
}
|
||||
|
||||
// CMPI $amD, #I
|
||||
// 0000 001r 1000 0000
|
||||
// CMPI $acD, #I
|
||||
// 0000 001d 1000 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
|
||||
// Although flags are being set regarding whole accumulator register.
|
||||
// Compares accumulator with immediate. Comparison is executed
|
||||
// by subtracting the immediate (16-bit sign extended) from mid accumulator
|
||||
// $acD.hm and computing flags based on whole accumulator $acD.
|
||||
//
|
||||
// flags out: x-xx xxxx
|
||||
void DSPEmitter::cmpi(const UDSPInstruction opc)
|
||||
@ -257,7 +258,7 @@ void DSPEmitter::cmpi(const UDSPInstruction opc)
|
||||
// CMPIS $acD, #I
|
||||
// 0000 011d iiii iiii
|
||||
// Compares accumulator with short immediate. Comparison is executed
|
||||
// by subtracting short immediate (8bit sign extended) from mid accumulator
|
||||
// by subtracting the short immediate (8-bit sign extended) from mid accumulator
|
||||
// $acD.hm and computing flags based on whole accumulator $acD.
|
||||
//
|
||||
// flags out: x-xx xxxx
|
||||
@ -472,7 +473,7 @@ void DSPEmitter::notc(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// XORI $acD.m, #I
|
||||
// 0000 001r 0010 0000
|
||||
// 0000 001d 0010 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic exclusive or (XOR) of accumulator mid part $acD.m with
|
||||
// immediate value I.
|
||||
@ -498,7 +499,7 @@ void DSPEmitter::xori(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ANDI $acD.m, #I
|
||||
// 0000 001r 0100 0000
|
||||
// 0000 001d 0100 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic AND of accumulator mid part $acD.m with immediate value I.
|
||||
//
|
||||
@ -523,7 +524,7 @@ void DSPEmitter::andi(const UDSPInstruction opc)
|
||||
}
|
||||
|
||||
// ORI $acD.m, #I
|
||||
// 0000 001r 0110 0000
|
||||
// 0000 001d 0110 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Logic OR of accumulator mid part $acD.m with immediate value I.
|
||||
//
|
||||
@ -706,8 +707,8 @@ void DSPEmitter::addaxl(const UDSPInstruction opc)
|
||||
}
|
||||
}
|
||||
|
||||
// ADDI $amR, #I
|
||||
// 0000 001r 0000 0000
|
||||
// ADDI $acD, #I
|
||||
// 0000 001d 0000 0000
|
||||
// iiii iiii iiii iiii
|
||||
// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
|
||||
//
|
||||
|
Reference in New Issue
Block a user