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:
Mai M
2022-06-02 20:26:31 -04:00
committed by GitHub
7 changed files with 567 additions and 102 deletions

View File

@ -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.
//

View File

@ -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);

View File

@ -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);

View File

@ -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.
//