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
commit f7f47d3cd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 // ANDCF $acD.m, #I
// 0000 001r 1100 0000 // 0000 001d 1100 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Set logic zero (LZ) flag in status register $sr if result of logic AND of // 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. // 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 // ANDF $acD.m, #I
// 0000 001r 1010 0000 // 0000 001d 1010 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Set logic zero (LZ) flag in status register $sr if result of logical AND // 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 // operation of accumulator mid part $acD.m with immediate value I is equal
@ -81,7 +81,7 @@ void Interpreter::andf(const UDSPInstruction opc)
// TST // TST
// 1011 r001 xxxx xxxx // 1011 r001 xxxx xxxx
// Test accumulator %acR. // Test accumulator $acR.
// //
// flags out: --xx xx00 // flags out: --xx xx00
void Interpreter::tst(const UDSPInstruction opc) void Interpreter::tst(const UDSPInstruction opc)
@ -143,11 +143,12 @@ void Interpreter::cmpaxh(const UDSPInstruction opc)
ZeroWriteBackLog(); ZeroWriteBackLog();
} }
// CMPI $amD, #I // CMPI $acD, #I
// 0000 001r 1000 0000 // 0000 001d 1000 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. // Compares accumulator with immediate. Comparison is executed
// Although flags are being set regarding whole accumulator register. // 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 // flags out: x-xx xxxx
void Interpreter::cmpi(const UDSPInstruction opc) void Interpreter::cmpi(const UDSPInstruction opc)
@ -166,8 +167,8 @@ void Interpreter::cmpi(const UDSPInstruction opc)
// CMPIS $acD, #I // CMPIS $acD, #I
// 0000 011d iiii iiii // 0000 011d iiii iiii
// Compares accumulator with short immediate. Comaprison is executed // 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. // $acD.hm and computing flags based on whole accumulator $acD.
// //
// flags out: x-xx xxxx // flags out: x-xx xxxx
@ -320,7 +321,7 @@ void Interpreter::notc(const UDSPInstruction opc)
} }
// XORI $acD.m, #I // XORI $acD.m, #I
// 0000 001r 0010 0000 // 0000 001d 0010 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic exclusive or (XOR) of accumulator mid part $acD.m with // Logic exclusive or (XOR) of accumulator mid part $acD.m with
// immediate value I. // immediate value I.
@ -337,7 +338,7 @@ void Interpreter::xori(const UDSPInstruction opc)
} }
// ANDI $acD.m, #I // ANDI $acD.m, #I
// 0000 001r 0100 0000 // 0000 001d 0100 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic AND of accumulator mid part $acD.m with immediate value I. // 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 // ORI $acD.m, #I
// 0000 001r 0110 0000 // 0000 001d 0110 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic OR of accumulator mid part $acD.m with immediate value I. // 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)); UpdateSR64Add(acc, acx, GetLongAcc(dreg));
} }
// ADDI $amR, #I // ADDI $acD, #I
// 0000 001r 0000 0000 // 0000 001d 0000 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. // Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
// //

View File

@ -16,8 +16,23 @@
namespace DSP::Interpreter namespace DSP::Interpreter
{ {
// Not needed for game ucodes (it slows down interpreter + easier to compare int VS // Correctly handle instructions such as `INC'L $ac0 : $ac0.l, @$ar0` (encoded as 0x7660) where both
// dspjit64 without it) // 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 //#define PRECISE_BACKLOG
Interpreter::Interpreter(DSPCore& dsp) : m_dsp_core{dsp} Interpreter::Interpreter(DSPCore& dsp) : m_dsp_core{dsp}
@ -809,7 +824,7 @@ void Interpreter::ConditionalExtendAccum(int reg)
void Interpreter::ApplyWriteBackLog() void Interpreter::ApplyWriteBackLog()
{ {
// Always make sure to have an extra entry at the end w/ -1 to avoid // 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++) for (int i = 0; m_write_back_log_idx[i] != -1; i++)
{ {
u16 value = m_write_back_log[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) void Interpreter::WriteToBackLog(int i, int idx, u16 value)
{ {
m_write_back_log[i] = value; m_write_back_log[i] = value;
@ -840,7 +860,7 @@ void Interpreter::ZeroWriteBackLog()
{ {
#ifdef PRECISE_BACKLOG #ifdef PRECISE_BACKLOG
// always make sure to have an extra entry at the end w/ -1 to avoid // 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++) for (int i = 0; m_write_back_log_idx[i] != -1; i++)
{ {
OpWriteRegister(m_write_back_log_idx[i], 0); OpWriteRegister(m_write_back_log_idx[i], 0);

View File

@ -235,11 +235,6 @@ private:
void ConditionalExtendAccum(int reg); 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 WriteToBackLog(int i, int idx, u16 value);
void ZeroWriteBackLog(); void ZeroWriteBackLog();
void ZeroWriteBackLogPreserveAcc(u8 acc); void ZeroWriteBackLogPreserveAcc(u8 acc);

View File

@ -53,7 +53,7 @@ void DSPEmitter::clrl(const UDSPInstruction opc)
//---- //----
// ANDCF $acD.m, #I // ANDCF $acD.m, #I
// 0000 001r 1100 0000 // 0000 001d 1100 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Set logic zero (LZ) flag in status register $sr if result of logic AND of // 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. // 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 // ANDF $acD.m, #I
// 0000 001r 1010 0000 // 0000 001d 1010 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Set logic zero (LZ) flag in status register $sr if result of logical AND // 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 // operation of accumulator mid part $acD.m with immediate value I is equal
@ -126,7 +126,7 @@ void DSPEmitter::andf(const UDSPInstruction opc)
// TST // TST
// 1011 r001 xxxx xxxx // 1011 r001 xxxx xxxx
// Test accumulator %acR. // Test accumulator $acR.
// //
// flags out: --xx xx00 // flags out: --xx xx00
void DSPEmitter::tst(const UDSPInstruction opc) void DSPEmitter::tst(const UDSPInstruction opc)
@ -220,11 +220,12 @@ void DSPEmitter::cmpaxh(const UDSPInstruction opc)
} }
} }
// CMPI $amD, #I // CMPI $acD, #I
// 0000 001r 1000 0000 // 0000 001d 1000 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. // Compares accumulator with immediate. Comparison is executed
// Although flags are being set regarding whole accumulator register. // 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 // flags out: x-xx xxxx
void DSPEmitter::cmpi(const UDSPInstruction opc) void DSPEmitter::cmpi(const UDSPInstruction opc)
@ -257,7 +258,7 @@ void DSPEmitter::cmpi(const UDSPInstruction opc)
// CMPIS $acD, #I // CMPIS $acD, #I
// 0000 011d iiii iiii // 0000 011d iiii iiii
// Compares accumulator with short immediate. Comparison is executed // 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. // $acD.hm and computing flags based on whole accumulator $acD.
// //
// flags out: x-xx xxxx // flags out: x-xx xxxx
@ -472,7 +473,7 @@ void DSPEmitter::notc(const UDSPInstruction opc)
} }
// XORI $acD.m, #I // XORI $acD.m, #I
// 0000 001r 0010 0000 // 0000 001d 0010 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic exclusive or (XOR) of accumulator mid part $acD.m with // Logic exclusive or (XOR) of accumulator mid part $acD.m with
// immediate value I. // immediate value I.
@ -498,7 +499,7 @@ void DSPEmitter::xori(const UDSPInstruction opc)
} }
// ANDI $acD.m, #I // ANDI $acD.m, #I
// 0000 001r 0100 0000 // 0000 001d 0100 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic AND of accumulator mid part $acD.m with immediate value I. // 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 // ORI $acD.m, #I
// 0000 001r 0110 0000 // 0000 001d 0110 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Logic OR of accumulator mid part $acD.m with immediate value I. // 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 // ADDI $acD, #I
// 0000 001r 0000 0000 // 0000 001d 0000 0000
// iiii iiii iiii iiii // iiii iiii iiii iiii
// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. // Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
// //

View File

@ -0,0 +1,202 @@
; This test covers the behavior of 40-bit mode with various instructions.
incdir "tests"
include "dsp_base.inc"
positive_value: EQU #0x1234
negative_value: EQU #0x9876
negative_imem_value_addr:
CW negative_value
; DSPSpy doesn't pre-populating DMEM currently, so instead use these addresses to store values.
positive_dmem_value_addr: EQU #0x100
negative_dmem_value_addr: EQU #0x101
readback_dmem_addr: EQU #0x102
test_main:
LRI $ar0, #positive_dmem_value_addr
LRI $ar1, #negative_dmem_value_addr
LRI $ar2, #negative_imem_value_addr
LRI $ar3, #readback_dmem_addr
LRI $ix0, #0
LRI $ix1, #0
LRI $ix2, #0
LRI $ix3, #0
LRI $ax0.h, #positive_value
LRI $ax1.h, #negative_value
SR @positive_dmem_value_addr, $ax0.h
SR @negative_dmem_value_addr, $ax1.h
LRI $cr, #(positive_dmem_value_addr / 256)
SET40
; Instructions that perform sign-extension
; $acc0 should alternate between being positive and negative here
; (though none of these instructions update $sr)
; [1] ILRR (also ILRRD/ILRRI/ILRRN, not covered)
ILRR $ac0.m, @$ar2 ; -
CALL send_back
; [2] LR
LR $ac0.m, @positive_dmem_value_addr ; +
CALL send_back
; [3] LRI
LRI $ac0.m, #negative_value ; -
CALL send_back
; [4] LRIS
LRIS $ac0.m, #42 ; +
CALL send_back
; [5] LRR (also LRRD/LRRI/LRRN)
LRR $ac0.m, @$ar1 ; -
CALL send_back
; [6] LRS
LRS $ac0.m, @(positive_dmem_value_addr & 0xff) ; +
CALL send_back
; [7] MRR
MRR $ac0.m, $ax1.h ; -
CALL send_back
; [8] 'LN (and 'L, but 'LN lets us set $ix0 to not increment $ar0)
NX'LN : $ac0.m, @$ar0 ; +
CALL send_back
; Instructions that experience saturation
; $ax1.l should alternate between 0x8000 and 0x7fff.
LRI $ac0.m, #0x4231
LRI $ac0.h, #0x12 ; positive
LRI $ac1.m, #0x2816
LRI $ac1.h, #0x99 ; negative
; [9] MRR (again)
MRR $ax1.l, $ac1.m ; -
CALL send_back
; [10] SR
SR @readback_dmem_addr, $ac0.m
LR $ax1.l, @readback_dmem_addr ; +
CALL send_back
; [11] SRRN (also SRR/SRRD/SRRI)
SRRN @$ar3, $ac1.m
LR $ax1.l, @readback_dmem_addr ; -
CALL send_back
; [12] SRS
SRS @(readback_dmem_addr & 0xff), $ac0.m
LR $ax1.l, @readback_dmem_addr ; +
CALL send_back
; [13] 'LSNM (also 'LS/'LSM/'LSN) - the $ax0.l read is not relevant
NX'LSNM : $ax0.l, $ac1.m
LR $ax1.l, @readback_dmem_addr ; -
CALL send_back
; [14] 'MV
NX'MV : $ax1.l, $ac0.m ; +
CALL send_back
; [15] 'SLNM (also 'SL/'SLM/'SLN) - the $ax0.l read is not relevant
; Note that 'SL stores to @$ar0, while 'LS stores to @$ar3
LRI $ar0, #readback_dmem_addr
NX'SLNM : $ac1.m, $ax0.l
LR $ax1.l, @readback_dmem_addr ; -
CALL send_back
LRI $ar0, #positive_dmem_value_addr
; [16] 'SN (also 'S)
NX'SN : @$ar3, $ac0.m
LR $ax1.l, @readback_dmem_addr ; +
CALL send_back
; Instructions that are not affected
; [17] ADDI
ADDI $ac0.m, #8
CALL send_back
; [18] ADDIS
ADDIS $ac0.m, #-8
CALL send_back
; [19] ANDC
ANDC $ac1.m, $ac0.m
CALL send_back
; [20] ANDI
ANDI $ac0.m, #0x6666
CALL send_back
; [21] ANDR
ANDR $ac0.m, $ax0.h
CALL send_back
; [22] ORC
ORC $ac0.m, $ac1.m
CALL send_back
; [23] ORI
ORI $ac0.m, #0xfeed
CALL send_back
; [24] ORR
ORR $ac1.m, $ax0.h
CALL send_back
; [25] NOT
NOT $ac1.m
CALL send_back
; [26] XORC
XORC $ac0.m, $ac1.m
CALL send_back
; [27] XORI
XORI $ac0.m, #0x5555
CALL send_back
; [28] XORR
XORR $ac1.m, $ax1.h
CALL send_back
; [29] MOVR always sign extends...
MOVR $acc1, $ax0.h
CALL send_back
; [30] ... even in SET16 mode
SET16
MOVR $acc1, $ax1.h
CALL send_back
SET40
; Shift instructions - do these see saturated $ac1.m?
LRI $ac0.m, #positive_value
LRI $ac1.m, #2
LRI $ac1.h, #1
; [31] - for diffs only
CALL send_back
; [32]
LSRNR $acc0, $ac1.m
CALL send_back
; [33] Shifts $acc0 by $ac1.m (in the other direction)
LSRN
CALL send_back
; Does LOOP experience saturation?
CLR $acc0
LRI $ac1.m, #0x1234
LRI $ac1.h, #1
; [34] - for diffs only
CALL send_back
; [35] LOOP
LOOP $ac1.m
INC $acc0
CALL send_back
LRI $ac1.h, #0x99
; [36] BLOOP
BLOOP $ac1.m, bloop_last_ins
INCM $ac0.m
bloop_last_ins:
NOP
CALL send_back
; For the sake of clarity, the same LOOP/BLOOP calls in SET16 mode don't have saturation:
SET16
CLR $acc0
LRI $ac1.m, #0x1234
LRI $ac1.h, #1
; [37] - for diffs only
CALL send_back
; [38] LOOP
LOOP $ac1.m
INC $acc0
CALL send_back
LRI $ac1.h, #0x99
; [39] BLOOP
BLOOP $ac1.m, bloop2_last_ins
INCM $ac0.m
bloop2_last_ins:
NOP
CALL send_back
; We're done, DO NOT DELETE THIS LINE
JMP end_of_test

View File

@ -0,0 +1,164 @@
; This test covers the behavior of 40-bit mode for a variety of values.
; It takes a while to run completely (~5 minutes), but progress is indicated via mail shown at the
; top of the screen in DSPSpy. The value will go from 80000000 to 8041ffff.
incdir "tests"
include "dsp_base.inc"
test_main:
LRI $ar0, #0
LRI $ar1, #0
LRI $ar2, #0
LRI $ar3, #0
LRI $ix0, #0
LRI $ix1, #0
LRI $ix2, #0
LRI $ix3, #0
; Test with $ac0.l from 0xfff0 to 0x0010
LRI $ac0.l, #0xfff0
BLOOPI #0x21, first_loop_last_ins
CALL test_saturation
IAR $ar0
first_loop_last_ins:
INC $acc0
; Test with $ac0.l from 0x7ff0 to 0x8010
LRI $ac0.l, #0xfff0
BLOOPI #0x21, second_loop_last_ins
CALL test_saturation
IAR $ar0
second_loop_last_ins:
INC $acc0
; We're done. Report the test results.
; $ix1 should be 0, or else saturation occurred on $ac0.l or $ac0.h.
; $ix2 should be 0, or else sign-extension occurred on $ac0.l or $ac0.h.
; $ix3 should be 0, or else we incorrectly predicted saturation on $ac0.m.
; $ar1/$ar2/$ar3 records the number of times it happened
CALL send_back
; We're done, DO NOT DELETE THIS LINE
JMP end_of_test
test_saturation:
; We start with $ac0.h at -0x80 since we can use the overflow flag to check when wrapping around
; occurs; starting at 0 and ending when it wraps back to 0 doesn't work since we can't check the
; zero flag since $ac0.l may be nonzero ($ac0.l is used as an input to this subroutine)
LRI $ac0.m, #0
LRI $ac0.h, #-0x80
loop_start:
; Compare the value of $ac0.m when in SET16 mode and in SET40 mode
SET40
; Reading $ac0.m in SET40 mode results in saturation if $ac0.h doesn't match the sign-extension
; of $ac0.h. Also, storing to $ac1.m in SET40 mode clears $ac1.l and sets $ac1.h to the
; sign-extension of $ac1.m, and $ac1.l.
MRR $ac1.m, $ac0.m
SET16
; Attempt to compute the saturated value of $ac1.m in $ax1.h,
; using what we know of $acc0.
TST'MV $acc0 : $ax1.h, $ac0.m
JL negative_acc0
; $acc0 is nonnegative.
JMPx8 check_saturated_ax1h ; If the above s32 bit is not set, we don't need to saturate
; If the above s32 bit _is_ set, then saturate $ax1.h.
LRI $ax1.h, #0x7fff
JMP check_saturated_ax1h
negative_acc0:
JMPx8 check_saturated_ax1h ; If the above s32 bit is not set, we don't need to saturate
LRI $ax1.h, #0x8000
; Fall through to check_saturated_ax1h
check_saturated_ax1h:
; $acc1 has the value of $ac0.m in SET40 mode.
; And, $ax1.h has what we computed that value should be, and CMPAXH always sign-extends $ax1.h
; (and ignores $ax1.l), so we can compare using it directly.
CMPAXH $acc1, $ax1.h
JZ check_read_low
; Our prediction was wrong (shouldn't happen)
LRI $ix3, #1
IAR $ar3
TST $acc0
CALL send_back
; Fall through to check_read_low
check_read_low:
SET40
MRR $ac1.m, $ac0.l
SET16
MRR $ax1.h, $ac0.l
CMPAXH $acc1, $ax1.h
JZ check_read_high
; Reading $ac0.l gave different results in SET40 and SET16 modes (shouldn't happen)
LRI $ix1, #1
IAR $ar1
TST $acc0
CALL send_back
; Fall through to check_read_high
check_read_high:
SET40
MRR $ac1.m, $ac0.h
SET16
MRR $ax1.h, $ac0.h
CMPAXH $acc1, $ax1.h
JZ check_write_low
; Reading $ac0.h gave different results in SET40 and SET16 modes (shouldn't happen)
LRI $ix1, #1
IAR $ar1
TST $acc0
CALL send_back
; Fall through to check_write_low
check_write_low:
MOV $acc1, $acc0
SET40
MRR $ac1.l, $ac0.l
SET16
CMP
JZ check_write_high
; Writing to $ac1.l caused $acc1 to not match $acc0 (shouldn't happen)
LRI $ix2, #1
IAR $ar2
CALL send_back
; Fall through to check_write_high
check_write_high:
MOV $acc1, $acc0
SET40
MRR $ac1.h, $ac0.h
SET16
CMP
JZ increment_loop
; Writing to $ac1.h caused $acc1 to not match $acc0 (shouldn't happen)
LRI $ix2, #1
IAR $ar2
CALL send_back
; Fall through to increment_loop
increment_loop:
INCM $ac0.m
; If incrementing results in overflowing, then we're done.
RETO
; If ($ac0.m & 0x00ff) != 0, continue the loop without sending mail.
ANDF $ac0.m, #0x00ff
JLNZ loop_start
; Otherwise, send mail to report the progress. (This shows at the top of the screen in DSPSpy,
; but otherwise isn't handled in any meaningful way.)
MOV $acc1, $acc0
LSR $acc1, #-8
; Compensate for starting at INT_MIN (0x80'0000'0000) and ending at INT_MAX (0x7f'0000'0000)
; instead of going from 0 (0x00'0000'0000) to -1 (0xff'ffff'ffff)
XORI $ac1.m, #0x8000
SR @DMBH, $ar0
SR @DMBL, $ac1.m
SI @DIRQ, #0x0001
; We don't wait for the mail to be read, because we don't care about the response.
JMP loop_start

View File

@ -46,7 +46,7 @@
% Document front page material % Document front page material
\title{\textbf{\Huge GameCube DSP User's Manual}} \title{\textbf{\Huge GameCube DSP User's Manual}}
\author{Reverse-engineered and documented by Duddie \\ \href{mailto:duddie@walla.com}{duddie@walla.com}} \author{Reverse-engineered and documented by Duddie \\ \href{mailto:duddie@walla.com}{duddie@walla.com}}
\date{\today\\v0.1.3} \date{\today\\v0.1.4}
% Title formatting commands % Title formatting commands
\newcommand{\OpcodeTitle}[1]{\subsection{#1}\label{instruction:#1}} \newcommand{\OpcodeTitle}[1]{\subsection{#1}\label{instruction:#1}}
@ -261,6 +261,7 @@ The purpose of this documentation is purely academic and it aims at understandin
0.1.1 & 2022.05.14 & xperia64 & Added tested DSP bootloading transfer size \\ \hline 0.1.1 & 2022.05.14 & xperia64 & Added tested DSP bootloading transfer size \\ \hline
0.1.2 & 2022.05.21 & Pokechu22 & Fixed ``ILLR'' typo in Instruction Memory section \\ \hline 0.1.2 & 2022.05.21 & Pokechu22 & Fixed ``ILLR'' typo in Instruction Memory section \\ \hline
0.1.3 & 2022.05.27 & Pokechu22 & Renamed \texttt{CMPAR} instruction to \texttt{CMPAXH} \\ \hline 0.1.3 & 2022.05.27 & Pokechu22 & Renamed \texttt{CMPAR} instruction to \texttt{CMPAXH} \\ \hline
0.1.4 & 2022.06.02 & Pokechu22 & Fixed typos; added sections on 16-bit and 40-bit modes and on main and extended opcode writing to the same register. \\ \hline
\end{tabular} \end{tabular}
\end{table} \end{table}
@ -505,7 +506,7 @@ The high parts of the 40-bit accumulators (\Register{acX.h}) are sign-extended 8
and the upper 8 bits read the same as the 7th bit. For instance, \Value{0x007F} reads back as \Value{0x007F}, but \Value{0x0080} reads and the upper 8 bits read the same as the 7th bit. For instance, \Value{0x007F} reads back as \Value{0x007F}, but \Value{0x0080} reads
back as \Value{0xFF80}. back as \Value{0xFF80}.
\textbf{Accumulators \Register{\$acX}:} \subsection{Accumulators \Register{\$acX}}
40-bit accumulator \Register{\$acX} (\Register{\$acX.hml}) consists of registers: 40-bit accumulator \Register{\$acX} (\Register{\$acX.hml}) consists of registers:
@ -513,7 +514,7 @@ back as \Value{0xFF80}.
$acX = $acX.h << 32 | $acX.m << 16 | $acX.l $acX = $acX.h << 32 | $acX.m << 16 | $acX.l
\end{lstlisting} \end{lstlisting}
\textbf{Short accumulators \Register{\$acs.X}:} \subsection{Short accumulators \Register{\$acsX}}
24-bit accumulator \Register{\$acsX} (\Register{\$acX.hm}) consists of the upper 24 bits of accumulator \Register{\$acX}. 24-bit accumulator \Register{\$acsX} (\Register{\$acX.hm}) consists of the upper 24 bits of accumulator \Register{\$acX}.
@ -521,12 +522,30 @@ $acX = $acX.h << 32 | $acX.m << 16 | $acX.l
$acsX = $acX.h << 16 | $acX.m $acsX = $acX.h << 16 | $acX.m
\end{lstlisting} \end{lstlisting}
\textbf{Additional accumulators \Register{\$axX}:} \subsection{Additional accumulators \Register{\$axX}}
32-bit accumulators \Register{\$axX} (\Register{\$axX.hl}) consist of registers:
\begin{lstlisting}[language=C++] \begin{lstlisting}[language=C++]
$axX = $axX.h << 16 | $axX.l $axX = $axX.h << 16 | $axX.l
\end{lstlisting} \end{lstlisting}
\subsection{16-bit and 40-bit modes}\label{subsec:SET40}
Depending on the value of \RegisterField{\$sr.SXM} (bit 14), loading to \Register{\$acX.m} may also update \Register{\$acX.h} and \Register{\$acX.l}, and stores from \Register{\$acX.m} may experience saturation based on \Register{\$acX.h}. Regardless of the value of \RegisterField{\$sr.SXM}, arithmetic operations such as \Opcode{ADDI}, \Opcode{INCM}, \Opcode{MOVR}, and \Opcode{LSRN} will still affect the entire accumulator.
If \RegisterField{\$sr.SXM} is set to 0, then 16-bit mode (\Opcode{SET16}) is in use. Loads to \Register{\$acX.m} will only change \Register{\$acX.m}, and storing \Register{\$acX.m} will use the value directly contained in \Register{\$acX.m}; the same applies to loads to and stores from \Register{\$acX.h} or \Register{\$acX.l} or any other register.
If \RegisterField{\$sr.SXM} is set to 1, then 40-bit mode (\Opcode{SET40}) is in use. Loads to \Register{\$acX.m} will set \Register{\$acX.l} to 0 and will sign-extend into \Register{\$acX.h} (setting it to \Value{0xFF} if the sign bit is set (\InlineExpression{\$acX.m \& 0x8000 != 0}), and to 0 otherwise). This means that in 40-bit mode, loads to \Register{\$acX.m} are effectively loads to the whole accumulator \Register{\$acX}. Loads to \Register{\$acX.h} and \Register{\$acX.l} do not have this special behavior; they only modify the specified register (as in 16-bit mode).
Additionally, if \RegisterField{\$sr.SXM} is set to 1, then moving or storing from \Register{\$acX.m} may instead result in \Value{0x7fff} or \Value{0x8000} being used. This happens if \Register{\$acX.hml} is not the same as sign-extending \Register{\$acX.ml}; \Value{0x7fff} is used if \Register{\$acX} is positive and \Value{0x8000} is used if \Register{\$acX} is negative.
The conditions for this saturation are the same as the conditions for \RegisterField{\$sr.AS} (bit 4, above s32) to be set when flags are updated. (This does not mean that the saturation happens if and only if \RegisterField{\$sr.AS} is set, as the flags might have been set after an operation on a different register.)
The following instructions perform sign-extension when writing to \Register{\$acX.m}: \Opcode{ILRR}, \Opcode{ILRRD}, \Opcode{ILRRI}, and \Opcode{ILRRN}; \Opcode{LR}; \Opcode{LRI}; \Opcode{LRIS}; \Opcode{LRR}, \Opcode{LRRD}, \Opcode{LRRI}, and \Opcode{LRRN}; \Opcode{LRS}; \Opcode{MRR}; and \Opcode{'L} and \Opcode{'LN}.
The following instructions experience saturation when reading from \Register{\$acX.m}: \Opcode{BLOOP}; \Opcode{LOOP}; \Opcode{MRR}; \Opcode{SR}; \Opcode{SRR}, \Opcode{SRRD}, \Opcode{SRRI}, and \Opcode{SRRN}; \Opcode{SRS}; \Opcode{'LS}, \Opcode{'LSM}, \Opcode{'LSM}, and \Opcode{'LSNM}; \Opcode{'MV}; \Opcode{'SL}, \Opcode{'SLM}, \Opcode{'SLN}, and \Opcode{'SLNM}; and \Opcode{'S} and \Opcode{'SN}.
\pagebreak{} \pagebreak{}
\section{Stacks} \section{Stacks}
@ -569,8 +588,8 @@ Furthermore, it also contains control bits to configure the flow of certain oper
\begin{tabular}{|l|l|l|} \begin{tabular}{|l|l|l|}
\hline \hline
\textbf{Bit} & \textbf{Name} & \textbf{Comment} \\ \hline \textbf{Bit} & \textbf{Name} & \textbf{Comment} \\ \hline
\texttt{15} & \texttt{SU} & Operands are signed (1 = unsigned) \\ \hline \texttt{15} & \texttt{SU} & Multiplication operands are signed (1 = unsigned) \\ \hline
\texttt{14} & \texttt{SXM} & Sign extension mode (0 = \texttt{set16}, 1 = \texttt{set40}) \\ \hline \texttt{14} & \texttt{SXM} & Sign extension mode (1 = 40-bit, see \nameref{subsec:SET40}) \\ \hline
\texttt{13} & \texttt{AM} & Product multiply result by 2 (when \texttt{AM = 0}) \\ \hline \texttt{13} & \texttt{AM} & Product multiply result by 2 (when \texttt{AM = 0}) \\ \hline
\texttt{12} & & \\ \hline \texttt{12} & & \\ \hline
\texttt{11} & \texttt{EIE} & External interrupt enable \\ \hline \texttt{11} & \texttt{EIE} & External interrupt enable \\ \hline
@ -1217,12 +1236,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{ADDI} \begin{DSPOpcode}{ADDI}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{0000} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{0000} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
\begin{DSPOpcodeFormat} \begin{DSPOpcodeFormat}
ADDI $amR, #I ADDI $acD, #I
\end{DSPOpcodeFormat} \end{DSPOpcodeFormat}
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
@ -1356,7 +1375,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{ANDCF} \begin{DSPOpcode}{ANDCF}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{1100} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{1100} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
@ -1384,7 +1403,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{ANDF} \begin{DSPOpcode}{ANDF}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{1010} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{1010} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
@ -1412,7 +1431,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{ANDI} \begin{DSPOpcode}{ANDI}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{0100} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{0100} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
@ -1519,12 +1538,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (ac1.m & 64) IF ($ac1.m & 64)
IF (ac1.m & 63) != 0 IF ($ac1.m & 63) != 0
$ac0 >>= (64 - (ac1.m & 63)) $ac0 >>= (64 - ($ac1.m & 63))
ENDIF ENDIF
ELSE ELSE
$ac0 <<= ac1.m $ac0 <<= $ac1.m
ENDIF ENDIF
FLAGS($ac0) FLAGS($ac0)
$pc++ $pc++
@ -1547,12 +1566,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (ac(1-D).m & 64) IF ($ac(1-D).m & 64)
IF (ac(1-D).m & 63) != 0 IF ($ac(1-D).m & 63) != 0
$acD >>= (64 - (ac(1-D).m & 63)) $acD >>= (64 - ($ac(1-D).m & 63))
ENDIF ENDIF
ELSE ELSE
$acD <<= ac(1-D).m $acD <<= $ac(1-D).m
ENDIF ENDIF
FLAGS($acD) FLAGS($acD)
$pc++ $pc++
@ -1579,12 +1598,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (axS.h & 64) IF ($axS.h & 64)
IF (axS.h & 63) != 0 IF ($axS.h & 63) != 0
$acD >>= (64 - (axS.h & 63)) $acD >>= (64 - ($axS.h & 63))
ENDIF ENDIF
ELSE ELSE
$acD <<= axS.h $acD <<= $axS.h
ENDIF ENDIF
FLAGS($acD) FLAGS($acD)
$pc++ $pc++
@ -1634,6 +1653,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\Register{\$R} reaches zero. Block ends at specified address \Address{addrA} inclusive. i.e. opcode at \Address{addrA} is the last \Register{\$R} reaches zero. Block ends at specified address \Address{addrA} inclusive. i.e. opcode at \Address{addrA} is the last
opcode included in loop. Counter is pushed on loop stack \Register{\$st3}, end of block address is pushed on loop stack opcode included in loop. Counter is pushed on loop stack \Register{\$st3}, end of block address is pushed on loop stack
\Register{\$st2} and the repeat address is pushed on call stack \Register{\$st0}. Up to 4 nested loops are allowed. \Register{\$st2} and the repeat address is pushed on call stack \Register{\$st0}. Up to 4 nested loops are allowed.
\item When using \Register{\$ac0.m} or \Register{\$ac1.m} as the initial counter value, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -1953,17 +1973,17 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{CMPI} \begin{DSPOpcode}{CMPI}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{1000} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{1000} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
\begin{DSPOpcodeFormat} \begin{DSPOpcodeFormat}
CMPI $amD, #I CMPI $acD, #I
\end{DSPOpcodeFormat} \end{DSPOpcodeFormat}
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Compares mid accumulator \Register{\$acD.hm} (\Register{\$amD}) with sign-extended immediate value \Value{I}. \item Compares accumulator with immediate. Comparison is performed by subtracting the immediate (16-bit sign-extended)
However, flags are set with regards to the whole accumulator register. from mid accumulator \Register{\$acD.hm} and computing flags based on whole accumulator \Register{\$acD}.
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2138,6 +2158,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from instruction memory pointed by addressing register \Register{\$arS} \item Move value from instruction memory pointed by addressing register \Register{\$arS}
to mid accumulator register \Register{\$acD.m}. to mid accumulator register \Register{\$acD.m}.
\item Optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2160,6 +2181,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from instruction memory pointed by addressing register \Register{\$arS} \item Move value from instruction memory pointed by addressing register \Register{\$arS}
to mid accumulator register \Register{\$acD.m}. Decrement addressing register \Register{\$arS}. to mid accumulator register \Register{\$acD.m}. Decrement addressing register \Register{\$arS}.
\item Optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2183,6 +2205,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from instruction memory pointed by addressing register \Register{\$arS} to \item Move value from instruction memory pointed by addressing register \Register{\$arS} to
mid accumulator register \Register{\$acD.m}. Increment addressing register \Register{\$arS}. mid accumulator register \Register{\$acD.m}. Increment addressing register \Register{\$arS}.
\item Optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2207,6 +2230,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\item Move value from instruction memory pointed by addressing register \Register{\$arS} \item Move value from instruction memory pointed by addressing register \Register{\$arS}
to mid accumulator register \Register{\$acD.m}. Add corresponding indexing register to mid accumulator register \Register{\$acD.m}. Add corresponding indexing register
\Register{\$ixS} to addressing register \Register{\$arS}. \Register{\$ixS} to addressing register \Register{\$arS}.
\item Optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2367,6 +2391,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\item Repeatedly execute the following opcode until the counter specified by the value from register \Register{\$R} reaches zero. \item Repeatedly execute the following opcode until the counter specified by the value from register \Register{\$R} reaches zero.
Each execution decrements the counter. Register \Register{\$R} remains unchanged. If register \Register{\$R} is set to zero at the Each execution decrements the counter. Register \Register{\$R} remains unchanged. If register \Register{\$R} is set to zero at the
beginning of loop then the looped instruction will not get executed. beginning of loop then the looped instruction will not get executed.
\item When using \Register{\$ac0.m} or \Register{\$ac1.m} as the initial counter value, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2418,7 +2443,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by address \Address{M} to register \Register{\$D}. \item Move value from data memory pointed by address \Address{M} to register \Register{\$D}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2441,7 +2466,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Load immediate value \Value{I} to register \Register{\$D}. \item Load immediate value \Value{I} to register \Register{\$D}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2463,7 +2488,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Load immediate value \Value{I} (8-bit sign-extended) to accumulator register \Register{\$(0x18+D)}. \item Load immediate value \Value{I} (8-bit sign-extended) to accumulator register \Register{\$(0x18+D)}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2485,7 +2510,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}. \item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2508,7 +2533,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}. \item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}.
Decrements register \Register{\$arS}. Decrements register \Register{\$arS}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2532,7 +2557,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}. \item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}.
Increments register \Register{\$arS}. Increments register \Register{\$arS}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2556,7 +2581,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}. \item Move value from data memory pointed by addressing register \Register{\$arS} to register \Register{\$D}.
Add indexing register \Register{\$ixS} to register \Register{\$arS}. Add indexing register \Register{\$ixS} to register \Register{\$arS}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2579,7 +2604,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from data memory pointed by address \Address{(\$cr << 8) | M} to register \Register{\$(0x18+D)}. \item Move value from data memory pointed by address \Address{(\$cr << 8) | M} to register \Register{\$(0x18+D)}.
Perform an additional operation depending on destination register. \item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -2588,7 +2613,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote} \begin{DSPOpcodeNote}
\item \Opcode{LRS} can use \Register{\$axD} and cannot use \Register{\$acS.h}, while \Opcode{SRS} and \Opcode{SRSH} only work on \Register{\$acS}. \item \Opcode{LRS} can use \Register{\$axD}, but cannot use \Register{\$acD.h}, while \Opcode{SRS} and \Opcode{SRSH} only work on \Register{\$acS}.
\end{DSPOpcodeNote} \end{DSPOpcodeNote}
\DSPOpcodeFlagsUnchanged \DSPOpcodeFlagsUnchanged
@ -2676,12 +2701,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (ac1.m & 64) IF ($ac1.m & 64)
IF (ac1.m & 63) != 0 IF ($ac1.m & 63) != 0
$ac0 >>= (64 - (ac1.m & 63)) $ac0 >>= (64 - ($ac1.m & 63))
ENDIF ENDIF
ELSE ELSE
$ac0 <<= ac1.m $ac0 <<= $ac1.m
ENDIF ENDIF
FLAGS($ac0) FLAGS($ac0)
$pc++ $pc++
@ -2704,12 +2729,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (ac(1-D).m & 64) IF ($ac(1-D).m & 64)
IF (ac(1-D).m & 63) != 0 IF ($ac(1-D).m & 63) != 0
$acD >>= (64 - (ac(1-D).m & 63)) $acD >>= (64 - ($ac(1-D).m & 63))
ENDIF ENDIF
ELSE ELSE
$acD <<= ac(1-D).m $acD <<= $ac(1-D).m
ENDIF ENDIF
FLAGS($acD) FLAGS($acD)
$pc++ $pc++
@ -2736,12 +2761,12 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
IF (axS.h & 64) IF ($axS.h & 64)
IF (axS.h & 63) != 0 IF ($axS.h & 63) != 0
$acD >>= (64 - (axS.h & 63)) $acD >>= (64 - ($axS.h & 63))
ENDIF ENDIF
ELSE ELSE
$acD <<= axS.h $acD <<= $axS.h
ENDIF ENDIF
FLAGS($acD) FLAGS($acD)
$pc++ $pc++
@ -3049,7 +3074,8 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value from register \Register{\$S} to register \Register{\$D}. \item Move value from register \Register{\$S} to register \Register{\$D}.
Perform an additional operation depending on destination register. \item When moving to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\item When moving from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -3629,7 +3655,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{ORI} \begin{DSPOpcode}{ORI}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{0110} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{0110} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
@ -3861,6 +3887,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeSeeAlso} \begin{DSPOpcodeSeeAlso}
\item \Opcode{SET40} \item \Opcode{SET40}
\item \nameref{subsec:SET40}
\end{DSPOpcodeSeeAlso} \end{DSPOpcodeSeeAlso}
\DSPOpcodeFlagsUnchanged \DSPOpcodeFlagsUnchanged
@ -3886,6 +3913,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeSeeAlso} \begin{DSPOpcodeSeeAlso}
\item \Opcode{SET16} \item \Opcode{SET16}
\item \nameref{subsec:SET40}
\end{DSPOpcodeSeeAlso} \end{DSPOpcodeSeeAlso}
\DSPOpcodeFlagsUnchanged \DSPOpcodeFlagsUnchanged
@ -3929,7 +3957,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from register \Register{\$S} to a memory pointed by address \Address{M}. \item Store value from register \Register{\$S} to a memory pointed by address \Address{M}.
Perform an additional operation depending on destination register. \item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -3951,7 +3979,8 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from source register \Register{\$S} to a memory location pointed by addressing \item Store value from source register \Register{\$S} to a memory location pointed by addressing
register \Register{\$arD}. Perform an additional operation depending on source register. register \Register{\$arD}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -3973,7 +4002,8 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from source register \Register{\$S} to a memory location pointed by addressing \item Store value from source register \Register{\$S} to a memory location pointed by addressing
register \Register{\$arD}. Decrement register \Register{\$arD}. Perform an additional operation depending on source register. register \Register{\$arD}. Decrement register \Register{\$arD}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -3996,7 +4026,8 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from source register \Register{\$S} to a memory location pointed by addressing \item Store value from source register \Register{\$S} to a memory location pointed by addressing
register \Register{\$arD}. Increment register \Register{\$arD}. Perform an additional operation depending on source register. register \Register{\$arD}. Increment register \Register{\$arD}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4020,7 +4051,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from source register \Register{\$S} to a memory location pointed by addressing \item Store value from source register \Register{\$S} to a memory location pointed by addressing
register \Register{\$arD}. Add indexing register \Register{\$ixD} to register \Register{\$arD}. register \Register{\$arD}. Add indexing register \Register{\$ixD} to register \Register{\$arD}.
Perform an additional operation depending on source register. \item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4043,7 +4074,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from register \Register{\$(0x1C+S)} to a memory pointed by address \Address{(\$cr << 8) | M}. \item Store value from register \Register{\$(0x1C+S)} to a memory pointed by address \Address{(\$cr << 8) | M}.
Perform an additional operation depending on destination register. \item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4070,7 +4101,6 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value from register \Register{\$acS.h} to a memory pointed by address \Address{(\$cr << 8) | M}. \item Store value from register \Register{\$acS.h} to a memory pointed by address \Address{(\$cr << 8) | M}.
Perform an additional operation depending on destination register.
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4286,7 +4316,7 @@ A ``-'' indicates that the flag retains its previous value, a ``0'' indicates th
\begin{DSPOpcode}{XORI} \begin{DSPOpcode}{XORI}
\begin{DSPOpcodeBytefield}{16} \begin{DSPOpcodeBytefield}{16}
\monobitbox{4}{0000} & \monobitbox{4}{001r} & \monobitbox{4}{0010} & \monobitbox{4}{0000} \\ \monobitbox{4}{0000} & \monobitbox{4}{001d} & \monobitbox{4}{0010} & \monobitbox{4}{0000} \\
\monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii} & \monobitbox{4}{iiii}
\end{DSPOpcodeBytefield} \end{DSPOpcodeBytefield}
@ -4339,9 +4369,16 @@ Extended opcodes do not exist on their own. These opcodes can only be attached t
Specifically, opcodes where the first nybble is 0, 1, or 2 cannot be extended. Specifically, opcodes where the first nybble is 0, 1, or 2 cannot be extended.
Opcodes where the first nybble is 4 or higher can be extended, using the 8 lower bits. Opcodes where the first nybble is 4 or higher can be extended, using the 8 lower bits.
Opcodes where the first nybble is 3 can also be extended, but the main opcode is 9 bits and the extension opcode is 7 bits. For these instructions, the extension opcode is treated as if the first bit were 0 (i.e. \texttt{0xxxxxxx}). Opcodes where the first nybble is 3 can also be extended, but the main opcode is 9 bits and the extension opcode is 7 bits. For these instructions, the extension opcode is treated as if the first bit were 0 (i.e. \texttt{0xxxxxxx}).
(\Opcode{NX} has no behavior of its own, so it can be used to get an extended opcode's behavior on its own.)
Extended opcodes do not modify the program counter (\Register{\$pc} register). Extended opcodes do not modify the program counter (\Register{\$pc} register).
Extended opcodes are run \textit{in parallel} with the main opcode; they see the same register state as the input. (For instance, \texttt{\Opcode{MOVR}\Opcode{'MV} \Register{\$ac1}, \Register{\$ax0.l} : \Register{\$ax0.l}, \Register{\$ac1.m}} (encoded as \Value{0x6113}) \textit{swaps} the values of \Register{\$ac1.m} and \Register{\$ax0.l} (and also extends the new value of \Register{\$ac1.m} into \Register{\$ac1.l} and \Register{\$ac1.h}).)
Since they are executed in parallel, the main and extension opcodes could theoretically write to the same registers. All opcodes that support extension only modify a main accumulator \Register{\$acD}, as well as \Register{\$prod}, \Register{\$sr}, and/or \Register{\$pc}, while the extension opcodes themselves generally only modify an additional accumulator \Register{\$axD} and addressing registers \Register{\$arS}. The exception is \Opcode{'L} and \Opcode{'LN}, which has the option of writing to \Register{\$acD}. Thus, \texttt{\Opcode{INC}\Opcode{'L} \Register{\$ac0} : \Register{\$ac0.l}, @\Register{\$ar0}} (encoded as \Value{0x7660}) increments \Register{\$ac0} (and thus \Register{\$ac0.l}), but also sets \Register{\$ac0.l} to the value in data memory at address \Register{\$ar0} and increments \Register{\$ar0}.
When the main and extension opcodes write to the same register, the register is set to the two values bitwise-or'd together. For the above example, \Register{\$ar0.l} would be set to \InlineExpression{(\Register{\$ar0.l} + 1) | MEM[\Register{\$ar0}]}. \textbf{Note that no official uCode writes to the same register twice like this.}
\pagebreak{} \pagebreak{}
\section{Alphabetical list of extended opcodes} \section{Alphabetical list of extended opcodes}
@ -4396,6 +4433,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$arS}. \item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$arS}.
Post increment register \Register{\$arS}. Post increment register \Register{\$arS}.
\item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4416,6 +4454,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$arS}. \item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$arS}.
Add indexing register \Register{\$ixS} to register \Register{\$arS}. Add indexing register \Register{\$ixS} to register \Register{\$arS}.
\item When loading to \Register{\$ac0.m} or \Register{\$ac1.m}, optionally perform sign extension depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4655,6 +4694,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}. \item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}.
Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}. Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}.
Increment both \Register{\$ar0} and \Register{\$ar3}. Increment both \Register{\$ar0} and \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4663,6 +4703,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0++ $ar0++
$ar3++ $ar3++
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'SL} in that \Register{\$(0x18+D)} is associated with \Register{\$ar0} instead of \Register{\$ar3} and \Register{\$acS.m} is associated with \Register{\$ar3} instead of \Register{\$ar0}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'LSM} \begin{DSPOpcode}{'LSM}
@ -4678,6 +4722,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}. \item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}.
Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}. Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix3} to addressing register \Register{\$ar3} and increment \Register{\$ar0}. Add corresponding indexing register \Register{\$ix3} to addressing register \Register{\$ar3} and increment \Register{\$ar0}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4686,6 +4731,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0++ $ar0++
$ar3 += $ix3 $ar3 += $ix3
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'SLM} in that \Register{\$(0x18+D)} is associated with \Register{\$ar0} instead of \Register{\$ar3} and \Register{\$acS.m} is associated with \Register{\$ar3} instead of \Register{\$ar0}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'LSNM} \begin{DSPOpcode}{'LSNM}
@ -4702,6 +4751,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}. Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and add corresponding Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and add corresponding
indexing register \Register{\$ix3} to addressing register \Register{\$ar3}. indexing register \Register{\$ix3} to addressing register \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4710,6 +4760,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0 += $ix0 $ar0 += $ix0
$ar3 += $ix3 $ar3 += $ix3
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'SLNM} in that \Register{\$(0x18+D)} is associated with \Register{\$ar0} instead of \Register{\$ar3} and \Register{\$acS.m} is associated with \Register{\$ar3} instead of \Register{\$ar0}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'LSN} \begin{DSPOpcode}{'LSN}
@ -4725,6 +4779,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}. \item Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar0}.
Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}. Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and increment \Register{\$ar3}. Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and increment \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4733,6 +4788,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0 += $ix0 $ar0 += $ix0
$ar3++ $ar3++
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'SLN} in that \Register{\$(0x18+D)} is associated with \Register{\$ar0} instead of \Register{\$ar3} and \Register{\$acS.m} is associated with \Register{\$ar3} instead of \Register{\$ar0}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'MV} \begin{DSPOpcode}{'MV}
@ -4746,6 +4805,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Move value of register \Register{\$(0x1c+S)} to the register \Register{\$(0x18+D)}. \item Move value of register \Register{\$(0x1c+S)} to the register \Register{\$(0x18+D)}.
\item When moving from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4767,7 +4827,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeNote} \begin{DSPOpcodeNote}
\item Generally written as by not including any extension operation, such as writing \texttt{INC \$ac0} instead of writing \texttt{INC'NOP \$ac0}. \item Generally written by not including any extension operation, such as writing \texttt{INC \$ac0} instead of writing \texttt{INC'NOP \$ac0}.
\end{DSPOpcodeNote} \end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
@ -4801,6 +4861,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value of register \Register{\$(0x1c+S)} in the memory pointed by register \Register{\$arD}. \item Store value of register \Register{\$(0x1c+S)} in the memory pointed by register \Register{\$arD}.
Post increment register \Register{\$arD}. Post increment register \Register{\$arD}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4822,6 +4883,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}. \item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}.
Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}. Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}.
Increment both \Register{\$ar0} and \Register{\$ar3}. Increment both \Register{\$ar0} and \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4830,6 +4892,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0++ $ar0++
$ar3++ $ar3++
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'LS} in that \Register{\$(0x18+D)} is associated with \Register{\$ar3} instead of \Register{\$ar0} and \Register{\$acS.m} is associated with \Register{\$ar0} instead of \Register{\$ar3}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'SLM} \begin{DSPOpcode}{'SLM}
@ -4845,6 +4911,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}. \item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}.
Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}. Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix3} to addressing register \Register{\$ar3} and increment \Register{\$ar0}. Add corresponding indexing register \Register{\$ix3} to addressing register \Register{\$ar3} and increment \Register{\$ar0}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4853,6 +4920,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0++ $ar0++
$ar3 += $ix3 $ar3 += $ix3
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'LSM} in that \Register{\$(0x18+D)} is associated with \Register{\$ar3} instead of \Register{\$ar0} and \Register{\$acS.m} is associated with \Register{\$ar0} instead of \Register{\$ar3}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'SLNM} \begin{DSPOpcode}{'SLNM}
@ -4869,6 +4940,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}. Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and add corresponding Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and add corresponding
indexing register \Register{\$ix3} to addressing register \Register{\$ar3}. indexing register \Register{\$ix3} to addressing register \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4877,6 +4949,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0 += $ix0 $ar0 += $ix0
$ar3 += $ix3 $ar3 += $ix3
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'LSNM} in that \Register{\$(0x18+D)} is associated with \Register{\$ar3} instead of \Register{\$ar0} and \Register{\$acS.m} is associated with \Register{\$ar0} instead of \Register{\$ar3}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'SLN} \begin{DSPOpcode}{'SLN}
@ -4892,6 +4968,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}. \item Store value from register \Register{\$acS.m} to memory location pointed by register \Register{\$ar0}.
Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}. Load register \Register{\$(0x18+D)} with value from memory pointed by register \Register{\$ar3}.
Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and increment \Register{\$ar3}. Add corresponding indexing register \Register{\$ix0} to addressing register \Register{\$ar0} and increment \Register{\$ar3}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4900,6 +4977,10 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
$ar0 += $ix0 $ar0 += $ix0
$ar3++ $ar3++
\end{DSPOpcodeOperation} \end{DSPOpcodeOperation}
\begin{DSPOpcodeNote}
\item Differs from \Opcode{'LSN} in that \Register{\$(0x18+D)} is associated with \Register{\$ar3} instead of \Register{\$ar0} and \Register{\$acS.m} is associated with \Register{\$ar0} instead of \Register{\$ar3}. In both cases, \Register{\$(0x18+D)} is loaded and \Register{\$acS.m} is stored.
\end{DSPOpcodeNote}
\end{DSPOpcode} \end{DSPOpcode}
\begin{DSPOpcode}{'SN} \begin{DSPOpcode}{'SN}
@ -4914,6 +4995,7 @@ Extended opcodes do not modify the program counter (\Register{\$pc} register).
\begin{DSPOpcodeDescription} \begin{DSPOpcodeDescription}
\item Store value of register \Register{\$(0x1c+S)} in the memory pointed by register \Register{\$arD}. \item Store value of register \Register{\$(0x1c+S)} in the memory pointed by register \Register{\$arD}.
Add indexing register \Register{\$ixD} to register \Register{\$arD}. Add indexing register \Register{\$ixD} to register \Register{\$arD}.
\item When storing from \Register{\$ac0.m} or \Register{\$ac1.m}, optionally apply saturation depending on the value of \RegisterField{\$sr.SXM} (see \nameref{subsec:SET40}).
\end{DSPOpcodeDescription} \end{DSPOpcodeDescription}
\begin{DSPOpcodeOperation} \begin{DSPOpcodeOperation}
@ -4953,13 +5035,13 @@ Instruction & Opcode & Page \\ \hline
\OpcodeRow{0000 0010 1101 cccc}{RETcc} \OpcodeRow{0000 0010 1101 cccc}{RETcc}
\OpcodeRow{0000 0010 1111 cccc}{RTIcc} \OpcodeRow{0000 0010 1111 cccc}{RTIcc}
\OpcodeRowSkip \OpcodeRowSkip
\OpcodeRow{0000 001r 0000 0000 iiii iiii iiii iiii}{ADDI} \OpcodeRow{0000 001d 0000 0000 iiii iiii iiii iiii}{ADDI}
\OpcodeRow{0000 001r 0010 0000 iiii iiii iiii iiii}{XORI} \OpcodeRow{0000 001d 0010 0000 iiii iiii iiii iiii}{XORI}
\OpcodeRow{0000 001r 0100 0000 iiii iiii iiii iiii}{ANDI} \OpcodeRow{0000 001d 0100 0000 iiii iiii iiii iiii}{ANDI}
\OpcodeRow{0000 001r 0110 0000 iiii iiii iiii iiii}{ORI} \OpcodeRow{0000 001d 0110 0000 iiii iiii iiii iiii}{ORI}
\OpcodeRow{0000 001r 1000 0000 iiii iiii iiii iiii}{CMPI} \OpcodeRow{0000 001d 1000 0000 iiii iiii iiii iiii}{CMPI}
\OpcodeRow{0000 001r 1010 0000 iiii iiii iiii iiii}{ANDF} \OpcodeRow{0000 001d 1010 0000 iiii iiii iiii iiii}{ANDF}
\OpcodeRow{0000 001r 1100 0000 iiii iiii iiii iiii}{ANDCF} \OpcodeRow{0000 001d 1100 0000 iiii iiii iiii iiii}{ANDCF}
\OpcodeRowSkip \OpcodeRowSkip
\OpcodeRow{0000 0010 1100 1010}{LSRN} \OpcodeRow{0000 0010 1100 1010}{LSRN}
\OpcodeRow{0000 0010 1100 1011}{ASRN} \OpcodeRow{0000 0010 1100 1011}{ASRN}