Skip to content
Permalink
Browse files
Merge pull request #10048 from Pokechu22/dsp-manual
Improvements to DSP manual
  • Loading branch information
Tilka committed Aug 22, 2021
2 parents 17a01c8 + 88d2a72 commit e7a30dd
Show file tree
Hide file tree
Showing 21 changed files with 2,279 additions and 502 deletions.
@@ -47,7 +47,7 @@ void Interpreter::clrl(const UDSPInstruction opc)
// 0000 001r 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 I.
// accumulator mid part $acD.m with immediate value I is equal to I.
//
// flags out: -x-- ----
void Interpreter::andcf(const UDSPInstruction opc)
@@ -64,7 +64,7 @@ void Interpreter::andcf(const UDSPInstruction opc)
// 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
// immediate value 0.
// to immediate value 0.
//
// flags out: -x-- ----
void Interpreter::andf(const UDSPInstruction opc)
@@ -126,8 +126,7 @@ void Interpreter::cmp(const UDSPInstruction)

// CMPAR $acS axR.h
// 110r s001 xxxx xxxx
// Compares accumulator $acS with accumulator axR.h.
// Not described by Duddie's doc - at least not as a separate instruction.
// Compares accumulator $acS with accumulator $axR.h.
//
// flags out: x-xx xxxx
void Interpreter::cmpar(const UDSPInstruction opc)
@@ -794,7 +793,7 @@ void Interpreter::movr(const UDSPInstruction opc)

// MOVAX $acD, $axS
// 0110 10sd xxxx xxxx
// Moves secondary accumulator $axS to accumulator $axD.
// Moves secondary accumulator $axS to accumulator $acD.
//
// flags out: --xx xx00
void Interpreter::movax(const UDSPInstruction opc)
@@ -812,7 +811,7 @@ void Interpreter::movax(const UDSPInstruction opc)

// MOV $acD, $ac(1-D)
// 0110 110d xxxx xxxx
// Moves accumulator $ax(1-D) to accumulator $axD.
// Moves accumulator $ac(1-D) to accumulator $acD.
//
// flags out: --x0 xx00
void Interpreter::mov(const UDSPInstruction opc)
@@ -76,9 +76,10 @@ void Interpreter::jcc(const UDSPInstruction opc)
}

// Generic jmpr implementation
// JMPcc $R
// JRcc $R
// 0001 0111 rrr0 cccc
// Jump to address; set program counter to a value from register $R.
// Jump to address if condition cc has been met. Set program counter to
// a value from register $R.
void Interpreter::jmprcc(const UDSPInstruction opc)
{
if (!CheckCondition(opc & 0xf))
@@ -116,7 +117,7 @@ void Interpreter::rti(const UDSPInstruction)
}

// HALT
// 0000 0000 0020 0001
// 0000 0000 0010 0001
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
void Interpreter::halt(const UDSPInstruction)
{
@@ -144,7 +144,7 @@ void Interpreter::l(const UDSPInstruction opc)
}

// LN $axD.D, @$arS
// xxxx xxxx 01dd d0ss
// xxxx xxxx 01dd d1ss
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
// Add indexing register $ixS to register $arS.
void Interpreter::ln(const UDSPInstruction opc)
@@ -327,17 +327,17 @@ void Interpreter::slnm(const UDSPInstruction opc)
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
}

// LD $ax0.d, $ax1.r, @$arS
// LD $ax0.D, $ax1.R, @$arS
// xxxx xxxx 11dr 00ss
// example for "nx'ld $AX0.L, $AX1.L, @$AR3"
// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L.
// Increments AR0 and AR3.
// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are
// not doing that!)
// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L.
// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not
// Load register $ax0.D (either $ax0.l or $ax0.h) with value from memory pointed by register $arS.
// Load register $ax1.R (either $ax1.l or $ax1.h) with value from memory pointed by register $ar3.
// Increment both $arS and $ar3.
// S cannot be 3, as that encodes LDAX. Thus $arS and $ar3 are known to be distinct.
// If $ar0 and $ar3 point into the same memory page (upper 6 bits of addr are the same -> games are
// not doing that!) then the value pointed by $ar0 is loaded to BOTH $ax0.D and $ax1.R.
// If $ar0 points into an invalid memory page (ie 0x2000), then $ax0.D keeps its old value. (not
// implemented yet)
// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not
// If $ar3 points into an invalid memory page, then $ax1.R gets the same value as $ax0.D. (not
// implemented yet)
void Interpreter::ld(const UDSPInstruction opc)
{
@@ -360,6 +360,9 @@ void Interpreter::ld(const UDSPInstruction opc)

// LDAX $axR, @$arS
// xxxx xxxx 11sr 0011
// Load register $axR.h with value from memory pointed by register $arS.
// Load register $axR.l with value from memory pointed by register $ar3.
// Increment both $arS and $ar3.
void Interpreter::ldax(const UDSPInstruction opc)
{
const u8 sreg = (opc >> 5) & 0x1;
@@ -378,7 +381,7 @@ void Interpreter::ldax(const UDSPInstruction opc)
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}

// LDN $ax0.d, $ax1.r, @$arS
// LDN $ax0.D, $ax1.R, @$arS
// xxxx xxxx 11dr 01ss
void Interpreter::ldn(const UDSPInstruction opc)
{
@@ -419,7 +422,7 @@ void Interpreter::ldaxn(const UDSPInstruction opc)
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
}

// LDM $ax0.d, $ax1.r, @$arS
// LDM $ax0.D, $ax1.R, @$arS
// xxxx xxxx 11dr 10ss
void Interpreter::ldm(const UDSPInstruction opc)
{
@@ -462,7 +465,7 @@ void Interpreter::ldaxm(const UDSPInstruction opc)
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
}

// LDNM $ax0.d, $ax1.r, @$arS
// LDNM $ax0.D, $ax1.R, @$arS
// xxxx xxxx 11dr 11ss
void Interpreter::ldnm(const UDSPInstruction opc)
{
@@ -13,7 +13,6 @@ namespace DSP::Interpreter
// Move value from register $(0x18+S) to data memory pointed by address
// 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 Interpreter::srs(const UDSPInstruction opc)
{
auto& state = m_dsp_core.DSPState();
@@ -86,9 +85,9 @@ void Interpreter::si(const UDSPInstruction opc)
state.WriteDMEM(addr, imm);
}

// LRR $D, @$S
// LRR $D, @$arS
// 0001 1000 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Move value from data memory pointed by addressing register $arS to register $D.
void Interpreter::lrr(const UDSPInstruction opc)
{
const u8 sreg = (opc >> 5) & 0x3;
@@ -100,10 +99,10 @@ void Interpreter::lrr(const UDSPInstruction opc)
ConditionalExtendAccum(dreg);
}

// LRRD $D, @$S
// LRRD $D, @$arS
// 0001 1000 1ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Decrement register $S.
// Move value from data memory pointed by addressing register $arS to register $D.
// Decrement register $arS.
void Interpreter::lrrd(const UDSPInstruction opc)
{
const u8 sreg = (opc >> 5) & 0x3;
@@ -116,10 +115,10 @@ void Interpreter::lrrd(const UDSPInstruction opc)
state.r.ar[sreg] = DecrementAddressRegister(sreg);
}

// LRRI $D, @$S
// LRRI $D, @$arS
// 0001 1001 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Increment register $S.
// Move value from data memory pointed by addressing register $arS to register $D.
// Increment register $arS.
void Interpreter::lrri(const UDSPInstruction opc)
{
const u8 sreg = (opc >> 5) & 0x3;
@@ -132,10 +131,10 @@ void Interpreter::lrri(const UDSPInstruction opc)
state.r.ar[sreg] = IncrementAddressRegister(sreg);
}

// LRRN $D, @$S
// LRRN $D, @$arS
// 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.
// Move value from data memory pointed by addressing register $arS to register $D.
// Add corresponding indexing register $ixS to register $arS.
void Interpreter::lrrn(const UDSPInstruction opc)
{
const u8 sreg = (opc >> 5) & 0x3;
@@ -148,10 +147,10 @@ void Interpreter::lrrn(const UDSPInstruction opc)
state.r.ar[sreg] = IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg]));
}

// SRR @$D, $S
// SRR @$arD, $S
// 0001 1010 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D.
// addressing register $arD.
void Interpreter::srr(const UDSPInstruction opc)
{
const u8 dreg = (opc >> 5) & 0x3;
@@ -164,10 +163,10 @@ void Interpreter::srr(const UDSPInstruction opc)
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
}

// SRRD @$D, $S
// SRRD @$arD, $S
// 0001 1010 1dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Decrement register $D.
// addressing register $arD. Decrement register $arD.
void Interpreter::srrd(const UDSPInstruction opc)
{
const u8 dreg = (opc >> 5) & 0x3;
@@ -182,10 +181,10 @@ void Interpreter::srrd(const UDSPInstruction opc)
state.r.ar[dreg] = DecrementAddressRegister(dreg);
}

// SRRI @$D, $S
// SRRI @$arD, $S
// 0001 1011 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Increment register $D.
// addressing register $arD. Increment register $arD.
void Interpreter::srri(const UDSPInstruction opc)
{
const u8 dreg = (opc >> 5) & 0x3;
@@ -200,10 +199,10 @@ void Interpreter::srri(const UDSPInstruction opc)
state.r.ar[dreg] = IncrementAddressRegister(dreg);
}

// SRRN @$D, $S
// SRRN @$arD, $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.
// addressing register $arD. Add corresponding indexing register $ixD to register $arD.
void Interpreter::srrn(const UDSPInstruction opc)
{
const u8 dreg = (opc >> 5) & 0x3;
@@ -122,8 +122,8 @@ void Interpreter::addarn(const UDSPInstruction opc)

// SBCLR #I
// 0001 0010 aaaa aiii
// bit of status register $sr. Bit number is calculated by adding 6 to
// immediate value I.
// Clear bit of status register $sr. Bit number is calculated by adding 6 to immediate value I;
// thus, bits 6 through 13 (LZ through AM) can be cleared with this instruction.
void Interpreter::sbclr(const UDSPInstruction opc)
{
auto& state = m_dsp_core.DSPState();
@@ -134,8 +134,8 @@ void Interpreter::sbclr(const UDSPInstruction opc)

// SBSET #I
// 0001 0011 aaaa aiii
// Set bit of status register $sr. Bit number is calculated by adding 6 to
// immediate value I.
// Set bit of status register $sr. Bit number is calculated by adding 6 to immediate value I;
// thus, bits 6 through 13 (LZ through AM) can be set with this instruction.
void Interpreter::sbset(const UDSPInstruction opc)
{
auto& state = m_dsp_core.DSPState();
@@ -247,7 +247,7 @@ void Interpreter::mulx(const UDSPInstruction opc)
}

// MULXAC $ax0.S, $ax1.T, $acR
// 101s t01r xxxx xxxx
// 101s t10r xxxx xxxx
// Add product register to accumulator register $acR. Multiply one part
// $ax0 by one part $ax1. Part is selected by S and
// T bits. Zero selects low part, one selects high part.
@@ -343,7 +343,7 @@ void Interpreter::mulc(const UDSPInstruction opc)
}

// MULCAC $acS.m, $axT.h, $acR
// 110s t10r xxxx xxxx
// 110s t10r xxxx xxxx
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
// secondary accumulator $axS (treat them both as signed). Add product
// register before multiplication to accumulator $acR.
@@ -372,7 +372,6 @@ void Interpreter::mulcac(const UDSPInstruction opc)
// Multiply mid part of accumulator register $acS.m by high part $axT.h of
// secondary accumulator $axT (treat them both as signed). Move product
// register before multiplication to accumulator $acR.
// possible mistake in duddie's doc axT.h rather than axS.h
//
// flags out: --xx xx0x
void Interpreter::mulcmv(const UDSPInstruction opc)
@@ -394,8 +393,7 @@ void Interpreter::mulcmv(const UDSPInstruction opc)
}

// MULCMVZ $acS.m, $axT.h, $acR
// 110s t01r xxxx xxxx
// (fixed possible bug in duddie's description, s->t)
// 110s t01r xxxx xxxx
// Multiply mid part of accumulator register $acS.m by high part $axT.h of
// secondary accumulator $axT (treat them both as signed). Move product
// register before multiplication to accumulator $acR, set (round) low part of
@@ -56,7 +56,7 @@ void DSPEmitter::clrl(const UDSPInstruction opc)
// 0000 001r 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 I.
// accumulator mid part $acD.m with immediate value I is equal to I.
//
// flags out: -x-- ----
void DSPEmitter::andcf(const UDSPInstruction opc)
@@ -91,7 +91,7 @@ void DSPEmitter::andcf(const UDSPInstruction opc)
// 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
// immediate value 0.
// to immediate value 0.
//
// flags out: -x-- ----
void DSPEmitter::andf(const UDSPInstruction opc)
@@ -185,8 +185,7 @@ void DSPEmitter::cmp(const UDSPInstruction opc)

// CMPAR $acS axR.h
// 110r s001 xxxx xxxx
// Compares accumulator $acS with accumulator axR.h.
// Not described by Duddie's doc - at least not as a separate instruction.
// Compares accumulator $acS with accumulator $axR.h.
//
// flags out: x-xx xxxx
void DSPEmitter::cmpar(const UDSPInstruction opc)
@@ -1090,7 +1089,7 @@ void DSPEmitter::movr(const UDSPInstruction opc)

// MOVAX $acD, $axS
// 0110 10sd xxxx xxxx
// Moves secondary accumulator $axS to accumulator $axD.
// Moves secondary accumulator $axS to accumulator $acD.
//
// flags out: --xx xx00
void DSPEmitter::movax(const UDSPInstruction opc)
@@ -1111,7 +1110,7 @@ void DSPEmitter::movax(const UDSPInstruction opc)

// MOV $acD, $ac(1-D)
// 0110 110d xxxx xxxx
// Moves accumulator $ax(1-D) to accumulator $axD.
// Moves accumulator $ac(1-D) to accumulator $acD.
//
// flags out: --x0 xx00
void DSPEmitter::mov(const UDSPInstruction opc)
@@ -156,9 +156,10 @@ void DSPEmitter::r_jmprcc(const UDSPInstruction opc)
WriteBranchExit();
}
// Generic jmpr implementation
// JMPcc $R
// JRcc $R
// 0001 0111 rrr0 cccc
// Jump to address; set program counter to a value from register $R.
// Jump to address if condition cc has been met. Set program counter to
// a value from register $R.
// NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit
void DSPEmitter::jmprcc(const UDSPInstruction opc)
{
@@ -270,7 +271,7 @@ void DSPEmitter::rti(const UDSPInstruction opc)
}

// HALT
// 0000 0000 0020 0001
// 0000 0000 0010 0001
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
void DSPEmitter::halt(const UDSPInstruction)
{

0 comments on commit e7a30dd

Please sign in to comment.