| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |