From 12d34eec9b3c4de21849424cc11d7589a803b40e Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 25 May 2022 18:47:49 -0700 Subject: [PATCH] DSPSpy: Add 40-bit mode tests --- Source/DSPSpy/tests/40bit_ins_test.ds | 202 ++++++++++++++++++++++++++ Source/DSPSpy/tests/40bit_test.ds | 164 +++++++++++++++++++++ 2 files changed, 366 insertions(+) create mode 100644 Source/DSPSpy/tests/40bit_ins_test.ds create mode 100644 Source/DSPSpy/tests/40bit_test.ds diff --git a/Source/DSPSpy/tests/40bit_ins_test.ds b/Source/DSPSpy/tests/40bit_ins_test.ds new file mode 100644 index 0000000000..9ed8ad5dbe --- /dev/null +++ b/Source/DSPSpy/tests/40bit_ins_test.ds @@ -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 diff --git a/Source/DSPSpy/tests/40bit_test.ds b/Source/DSPSpy/tests/40bit_test.ds new file mode 100644 index 0000000000..a2f2b24a5f --- /dev/null +++ b/Source/DSPSpy/tests/40bit_test.ds @@ -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