| /* |
| * "memcpy" implementation of SuperH |
| * |
| * Copyright (C) 1999 Niibe Yutaka |
| * Copyright (c) 2002 STMicroelectronics Ltd |
| * Modified from memcpy.S and micro-optimised for SH4 |
| * Stuart Menefy (stuart.menefy@st.com) |
| * |
| */ |
| #include <linux/linkage.h> |
| |
| /* |
| * void *memcpy(void *dst, const void *src, size_t n); |
| * |
| * It is assumed that there is no overlap between src and dst. |
| * If there is an overlap, then the results are undefined. |
| */ |
| |
| ! |
| ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. |
| ! |
| |
| ! Size is 16 or greater, and may have trailing bytes |
| |
| .balign 32 |
| .Lcase1: |
| ! Read a long word and write a long word at once |
| ! At the start of each iteration, r7 contains last long load |
| add #-1,r5 ! 79 EX |
| mov r4,r2 ! 5 MT (0 cycles latency) |
| |
| mov.l @(r0,r5),r7 ! 21 LS (2 cycles latency) |
| add #-4,r5 ! 50 EX |
| |
| add #7,r2 ! 79 EX |
| ! |
| #ifdef CONFIG_CPU_LITTLE_ENDIAN |
| ! 6 cycles, 4 bytes per iteration |
| 3: mov.l @(r0,r5),r1 ! 21 LS (latency=2) ! NMLK |
| mov r7, r3 ! 5 MT (latency=0) ! RQPO |
| |
| cmp/hi r2,r0 ! 57 MT |
| shll16 r3 ! 103 EX |
| |
| mov r1,r6 ! 5 MT (latency=0) |
| shll8 r3 ! 102 EX ! Oxxx |
| |
| shlr8 r6 ! 106 EX ! xNML |
| mov r1, r7 ! 5 MT (latency=0) |
| |
| or r6,r3 ! 82 EX ! ONML |
| bt/s 3b ! 109 BR |
| |
| mov.l r3,@-r0 ! 30 LS |
| #else |
| 3: mov.l @(r0,r5),r1 ! 21 LS (latency=2) ! KLMN |
| mov r7,r3 ! 5 MT (latency=0) ! OPQR |
| |
| cmp/hi r2,r0 ! 57 MT |
| shlr16 r3 ! 107 EX |
| |
| shlr8 r3 ! 106 EX ! xxxO |
| mov r1,r6 ! 5 MT (latency=0) |
| |
| shll8 r6 ! 102 EX ! LMNx |
| mov r1,r7 ! 5 MT (latency=0) |
| |
| or r6,r3 ! 82 EX ! LMNO |
| bt/s 3b ! 109 BR |
| |
| mov.l r3,@-r0 ! 30 LS |
| #endif |
| ! Finally, copy a byte at once, if necessary |
| |
| add #4,r5 ! 50 EX |
| cmp/eq r4,r0 ! 54 MT |
| |
| add #-6,r2 ! 50 EX |
| bt 9f ! 109 BR |
| |
| 8: cmp/hi r2,r0 ! 57 MT |
| mov.b @(r0,r5),r1 ! 20 LS (latency=2) |
| |
| bt/s 8b ! 109 BR |
| |
| mov.b r1,@-r0 ! 29 LS |
| |
| 9: rts |
| nop |
| |
| |
| ! |
| ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R... |
| ! |
| |
| ! Size is 16 or greater, and may have trailing bytes |
| |
| .balign 32 |
| .Lcase3: |
| ! Read a long word and write a long word at once |
| ! At the start of each iteration, r7 contains last long load |
| add #-3,r5 ! 79 EX |
| mov r4,r2 ! 5 MT (0 cycles latency) |
| |
| mov.l @(r0,r5),r7 ! 21 LS (2 cycles latency) |
| add #-4,r5 ! 50 EX |
| |
| add #7,r2 ! 79 EX |
| ! |
| #ifdef CONFIG_CPU_LITTLE_ENDIAN |
| ! 6 cycles, 4 bytes per iteration |
| 3: mov.l @(r0,r5),r1 ! 21 LS (latency=2) ! NMLK |
| mov r7, r3 ! 5 MT (latency=0) ! RQPO |
| |
| cmp/hi r2,r0 ! 57 MT |
| shll8 r3 ! 102 EX ! QPOx |
| |
| mov r1,r6 ! 5 MT (latency=0) |
| shlr16 r6 ! 107 EX |
| |
| shlr8 r6 ! 106 EX ! xxxN |
| mov r1, r7 ! 5 MT (latency=0) |
| |
| or r6,r3 ! 82 EX ! QPON |
| bt/s 3b ! 109 BR |
| |
| mov.l r3,@-r0 ! 30 LS |
| #else |
| 3: mov r7,r3 ! OPQR |
| shlr8 r3 ! xOPQ |
| mov.l @(r0,r5),r7 ! KLMN |
| mov r7,r6 |
| shll16 r6 |
| shll8 r6 ! Nxxx |
| or r6,r3 ! NOPQ |
| cmp/hi r2,r0 |
| bt/s 3b |
| mov.l r3,@-r0 |
| #endif |
| |
| ! Finally, copy a byte at once, if necessary |
| |
| add #6,r5 ! 50 EX |
| cmp/eq r4,r0 ! 54 MT |
| |
| add #-6,r2 ! 50 EX |
| bt 9f ! 109 BR |
| |
| 8: cmp/hi r2,r0 ! 57 MT |
| mov.b @(r0,r5),r1 ! 20 LS (latency=2) |
| |
| bt/s 8b ! 109 BR |
| |
| mov.b r1,@-r0 ! 29 LS |
| |
| 9: rts |
| nop |
| |
| ENTRY(memcpy) |
| |
| ! Calculate the invariants which will be used in the remainder |
| ! of the code: |
| ! |
| ! r4 --> [ ... ] DST [ ... ] SRC |
| ! [ ... ] [ ... ] |
| ! : : |
| ! r0 --> [ ... ] r0+r5 --> [ ... ] |
| ! |
| ! |
| |
| ! Short circuit the common case of src, dst and len being 32 bit aligned |
| ! and test for zero length move |
| |
| mov r6, r0 ! 5 MT (0 cycle latency) |
| or r4, r0 ! 82 EX |
| |
| or r5, r0 ! 82 EX |
| tst r6, r6 ! 86 MT |
| |
| bt/s 99f ! 111 BR (zero len) |
| tst #3, r0 ! 87 MT |
| |
| mov r4, r0 ! 5 MT (0 cycle latency) |
| add r6, r0 ! 49 EX |
| |
| mov #16, r1 ! 6 EX |
| bt/s .Lcase00 ! 111 BR (aligned) |
| |
| sub r4, r5 ! 75 EX |
| |
| ! Arguments are not nicely long word aligned or zero len. |
| ! Check for small copies, and if so do a simple byte at a time copy. |
| ! |
| ! Deciding on an exact value of 'small' is not easy, as the point at which |
| ! using the optimised routines become worthwhile varies (these are the |
| ! cycle counts for differnet sizes using byte-at-a-time vs. optimised): |
| ! size byte-at-time long word byte |
| ! 16 42 39-40 46-50 50-55 |
| ! 24 58 43-44 54-58 62-67 |
| ! 36 82 49-50 66-70 80-85 |
| ! However the penalty for getting it 'wrong' is much higher for long word |
| ! aligned data (and this is more common), so use a value of 16. |
| |
| cmp/gt r6,r1 ! 56 MT |
| |
| add #-1,r5 ! 50 EX |
| bf/s 6f ! 108 BR (not small) |
| |
| mov r5, r3 ! 5 MT (latency=0) |
| shlr r6 ! 104 EX |
| |
| mov.b @(r0,r5),r1 ! 20 LS (latency=2) |
| bf/s 4f ! 111 BR |
| |
| add #-1,r3 ! 50 EX |
| tst r6, r6 ! 86 MT |
| |
| bt/s 98f ! 110 BR |
| mov.b r1,@-r0 ! 29 LS |
| |
| ! 4 cycles, 2 bytes per iteration |
| 3: mov.b @(r0,r5),r1 ! 20 LS (latency=2) |
| |
| 4: mov.b @(r0,r3),r2 ! 20 LS (latency=2) |
| dt r6 ! 67 EX |
| |
| mov.b r1,@-r0 ! 29 LS |
| bf/s 3b ! 111 BR |
| |
| mov.b r2,@-r0 ! 29 LS |
| 98: |
| rts |
| nop |
| |
| 99: rts |
| mov r4, r0 |
| |
| ! Size is not small, so its worthwhile looking for optimisations. |
| ! First align destination to a long word boundary. |
| ! |
| ! r5 = normal value -1 |
| |
| 6: tst #3, r0 ! 87 MT |
| mov #3, r3 ! 6 EX |
| |
| bt/s 2f ! 111 BR |
| and r0,r3 ! 78 EX |
| |
| ! 3 cycles, 1 byte per iteration |
| 1: dt r3 ! 67 EX |
| mov.b @(r0,r5),r1 ! 19 LS (latency=2) |
| |
| add #-1, r6 ! 79 EX |
| bf/s 1b ! 109 BR |
| |
| mov.b r1,@-r0 ! 28 LS |
| |
| 2: add #1, r5 ! 79 EX |
| |
| ! Now select the appropriate bulk transfer code based on relative |
| ! alignment of src and dst. |
| |
| mov r0, r3 ! 5 MT (latency=0) |
| |
| mov r5, r0 ! 5 MT (latency=0) |
| tst #1, r0 ! 87 MT |
| |
| bf/s 1f ! 111 BR |
| mov #64, r7 ! 6 EX |
| |
| ! bit 0 clear |
| |
| cmp/ge r7, r6 ! 55 MT |
| |
| bt/s 2f ! 111 BR |
| tst #2, r0 ! 87 MT |
| |
| ! small |
| bt/s .Lcase0 |
| mov r3, r0 |
| |
| bra .Lcase2 |
| nop |
| |
| ! big |
| 2: bt/s .Lcase0b |
| mov r3, r0 |
| |
| bra .Lcase2b |
| nop |
| |
| ! bit 0 set |
| 1: tst #2, r0 ! 87 MT |
| |
| bt/s .Lcase1 |
| mov r3, r0 |
| |
| bra .Lcase3 |
| nop |
| |
| |
| ! |
| ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR |
| ! |
| |
| ! src, dst and size are all long word aligned |
| ! size is non-zero |
| |
| .balign 32 |
| .Lcase00: |
| mov #64, r1 ! 6 EX |
| mov r5, r3 ! 5 MT (latency=0) |
| |
| cmp/gt r6, r1 ! 56 MT |
| add #-4, r5 ! 50 EX |
| |
| bf .Lcase00b ! 108 BR (big loop) |
| shlr2 r6 ! 105 EX |
| |
| shlr r6 ! 104 EX |
| mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| |
| bf/s 4f ! 111 BR |
| add #-8, r3 ! 50 EX |
| |
| tst r6, r6 ! 86 MT |
| bt/s 5f ! 110 BR |
| |
| mov.l r1,@-r0 ! 30 LS |
| |
| ! 4 cycles, 2 long words per iteration |
| 3: mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| |
| 4: mov.l @(r0, r3), r2 ! 21 LS (latency=2) |
| dt r6 ! 67 EX |
| |
| mov.l r1, @-r0 ! 30 LS |
| bf/s 3b ! 109 BR |
| |
| mov.l r2, @-r0 ! 30 LS |
| |
| 5: rts |
| nop |
| |
| |
| ! Size is 16 or greater and less than 64, but may have trailing bytes |
| |
| .balign 32 |
| .Lcase0: |
| add #-4, r5 ! 50 EX |
| mov r4, r7 ! 5 MT (latency=0) |
| |
| mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| mov #4, r2 ! 6 EX |
| |
| add #11, r7 ! 50 EX |
| tst r2, r6 ! 86 MT |
| |
| mov r5, r3 ! 5 MT (latency=0) |
| bt/s 4f ! 111 BR |
| |
| add #-4, r3 ! 50 EX |
| mov.l r1,@-r0 ! 30 LS |
| |
| ! 4 cycles, 2 long words per iteration |
| 3: mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| |
| 4: mov.l @(r0, r3), r2 ! 21 LS (latency=2) |
| cmp/hi r7, r0 |
| |
| mov.l r1, @-r0 ! 30 LS |
| bt/s 3b ! 109 BR |
| |
| mov.l r2, @-r0 ! 30 LS |
| |
| ! Copy the final 0-3 bytes |
| |
| add #3,r5 ! 50 EX |
| |
| cmp/eq r0, r4 ! 54 MT |
| add #-10, r7 ! 50 EX |
| |
| bt 9f ! 110 BR |
| |
| ! 3 cycles, 1 byte per iteration |
| 1: mov.b @(r0,r5),r1 ! 19 LS |
| cmp/hi r7,r0 ! 57 MT |
| |
| bt/s 1b ! 111 BR |
| mov.b r1,@-r0 ! 28 LS |
| |
| 9: rts |
| nop |
| |
| ! Size is at least 64 bytes, so will be going round the big loop at least once. |
| ! |
| ! r2 = rounded up r4 |
| ! r3 = rounded down r0 |
| |
| .balign 32 |
| .Lcase0b: |
| add #-4, r5 ! 50 EX |
| |
| .Lcase00b: |
| mov r0, r3 ! 5 MT (latency=0) |
| mov #(~0x1f), r1 ! 6 EX |
| |
| and r1, r3 ! 78 EX |
| mov r4, r2 ! 5 MT (latency=0) |
| |
| cmp/eq r3, r0 ! 54 MT |
| add #0x1f, r2 ! 50 EX |
| |
| bt/s 1f ! 110 BR |
| and r1, r2 ! 78 EX |
| |
| ! copy initial words until cache line aligned |
| |
| mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| tst #4, r0 ! 87 MT |
| |
| mov r5, r6 ! 5 MT (latency=0) |
| add #-4, r6 ! 50 EX |
| |
| bt/s 4f ! 111 BR |
| add #8, r3 ! 50 EX |
| |
| tst #0x18, r0 ! 87 MT |
| |
| bt/s 1f ! 109 BR |
| mov.l r1,@-r0 ! 30 LS |
| |
| ! 4 cycles, 2 long words per iteration |
| 3: mov.l @(r0, r5), r1 ! 21 LS (latency=2) |
| |
| 4: mov.l @(r0, r6), r7 ! 21 LS (latency=2) |
| cmp/eq r3, r0 ! 54 MT |
| |
| mov.l r1, @-r0 ! 30 LS |
| bf/s 3b ! 109 BR |
| |
| mov.l r7, @-r0 ! 30 LS |
| |
| ! Copy the cache line aligned blocks |
| ! |
| ! In use: r0, r2, r4, r5 |
| ! Scratch: r1, r3, r6, r7 |
| ! |
| ! We could do this with the four scratch registers, but if src |
| ! and dest hit the same cache line, this will thrash, so make |
| ! use of additional registers. |
| ! |
| ! We also need r0 as a temporary (for movca), so 'undo' the invariant: |
| ! r5: src (was r0+r5) |
| ! r1: dest (was r0) |
| ! this can be reversed at the end, so we don't need to save any extra |
| ! state. |
| ! |
| 1: mov.l r8, @-r15 ! 30 LS |
| add r0, r5 ! 49 EX |
| |
| mov.l r9, @-r15 ! 30 LS |
| mov r0, r1 ! 5 MT (latency=0) |
| |
| mov.l r10, @-r15 ! 30 LS |
| add #-0x1c, r5 ! 50 EX |
| |
| mov.l r11, @-r15 ! 30 LS |
| |
| ! 16 cycles, 32 bytes per iteration |
| 2: mov.l @(0x00,r5),r0 ! 18 LS (latency=2) |
| add #-0x20, r1 ! 50 EX |
| mov.l @(0x04,r5),r3 ! 18 LS (latency=2) |
| mov.l @(0x08,r5),r6 ! 18 LS (latency=2) |
| mov.l @(0x0c,r5),r7 ! 18 LS (latency=2) |
| mov.l @(0x10,r5),r8 ! 18 LS (latency=2) |
| mov.l @(0x14,r5),r9 ! 18 LS (latency=2) |
| mov.l @(0x18,r5),r10 ! 18 LS (latency=2) |
| mov.l @(0x1c,r5),r11 ! 18 LS (latency=2) |
| movca.l r0,@r1 ! 40 LS (latency=3-7) |
| mov.l r3,@(0x04,r1) ! 33 LS |
| mov.l r6,@(0x08,r1) ! 33 LS |
| mov.l r7,@(0x0c,r1) ! 33 LS |
| |
| mov.l r8,@(0x10,r1) ! 33 LS |
| add #-0x20, r5 ! 50 EX |
| |
| mov.l r9,@(0x14,r1) ! 33 LS |
| cmp/eq r2,r1 ! 54 MT |
| |
| mov.l r10,@(0x18,r1) ! 33 LS |
| bf/s 2b ! 109 BR |
| |
| mov.l r11,@(0x1c,r1) ! 33 LS |
| |
| mov r1, r0 ! 5 MT (latency=0) |
| |
| mov.l @r15+, r11 ! 15 LS |
| sub r1, r5 ! 75 EX |
| |
| mov.l @r15+, r10 ! 15 LS |
| cmp/eq r4, r0 ! 54 MT |
| |
| bf/s 1f ! 109 BR |
| mov.l @r15+, r9 ! 15 LS |
| |
| rts |
| 1: mov.l @r15+, r8 ! 15 LS |
| sub r4, r1 ! 75 EX (len remaining) |
| |
| ! number of trailing bytes is non-zero |
| ! |
| ! invariants restored (r5 already decremented by 4) |
| ! also r1=num bytes remaining |
| |
| mov #4, r2 ! 6 EX |
| mov r4, r7 ! 5 MT (latency=0) |
| |
| add #0x1c, r5 ! 50 EX (back to -4) |
| cmp/hs r2, r1 ! 58 MT |
| |
| bf/s 5f ! 108 BR |
| add #11, r7 ! 50 EX |
| |
| mov.l @(r0, r5), r6 ! 21 LS (latency=2) |
| tst r2, r1 ! 86 MT |
| |
| mov r5, r3 ! 5 MT (latency=0) |
| bt/s 4f ! 111 BR |
| |
| add #-4, r3 ! 50 EX |
| cmp/hs r2, r1 ! 58 MT |
| |
| bt/s 5f ! 111 BR |
| mov.l r6,@-r0 ! 30 LS |
| |
| ! 4 cycles, 2 long words per iteration |
| 3: mov.l @(r0, r5), r6 ! 21 LS (latency=2) |
| |
| 4: mov.l @(r0, r3), r2 ! 21 LS (latency=2) |
| cmp/hi r7, r0 |
| |
| mov.l r6, @-r0 ! 30 LS |
| bt/s 3b ! 109 BR |
| |
| mov.l r2, @-r0 ! 30 LS |
| |
| ! Copy the final 0-3 bytes |
| |
| 5: cmp/eq r0, r4 ! 54 MT |
| add #-10, r7 ! 50 EX |
| |
| bt 9f ! 110 BR |
| add #3,r5 ! 50 EX |
| |
| ! 3 cycles, 1 byte per iteration |
| 1: mov.b @(r0,r5),r1 ! 19 LS |
| cmp/hi r7,r0 ! 57 MT |
| |
| bt/s 1b ! 111 BR |
| mov.b r1,@-r0 ! 28 LS |
| |
| 9: rts |
| nop |
| |
| ! |
| ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR.. |
| ! |
| |
| .balign 32 |
| .Lcase2: |
| ! Size is 16 or greater and less then 64, but may have trailing bytes |
| |
| 2: mov r5, r6 ! 5 MT (latency=0) |
| add #-2,r5 ! 50 EX |
| |
| mov r4,r2 ! 5 MT (latency=0) |
| add #-4,r6 ! 50 EX |
| |
| add #7,r2 ! 50 EX |
| 3: mov.w @(r0,r5),r1 ! 20 LS (latency=2) |
| |
| mov.w @(r0,r6),r3 ! 20 LS (latency=2) |
| cmp/hi r2,r0 ! 57 MT |
| |
| mov.w r1,@-r0 ! 29 LS |
| bt/s 3b ! 111 BR |
| |
| mov.w r3,@-r0 ! 29 LS |
| |
| bra 10f |
| nop |
| |
| |
| .balign 32 |
| .Lcase2b: |
| ! Size is at least 64 bytes, so will be going round the big loop at least once. |
| ! |
| ! r2 = rounded up r4 |
| ! r3 = rounded down r0 |
| |
| mov r0, r3 ! 5 MT (latency=0) |
| mov #(~0x1f), r1 ! 6 EX |
| |
| and r1, r3 ! 78 EX |
| mov r4, r2 ! 5 MT (latency=0) |
| |
| cmp/eq r3, r0 ! 54 MT |
| add #0x1f, r2 ! 50 EX |
| |
| add #-2, r5 ! 50 EX |
| bt/s 1f ! 110 BR |
| and r1, r2 ! 78 EX |
| |
| ! Copy a short word one at a time until we are cache line aligned |
| ! Normal values: r0, r2, r3, r4 |
| ! Unused: r1, r6, r7 |
| ! Mod: r5 (=r5-2) |
| ! |
| add #2, r3 ! 50 EX |
| |
| 2: mov.w @(r0,r5),r1 ! 20 LS (latency=2) |
| cmp/eq r3,r0 ! 54 MT |
| |
| bf/s 2b ! 111 BR |
| |
| mov.w r1,@-r0 ! 29 LS |
| |
| ! Copy the cache line aligned blocks |
| ! |
| ! In use: r0, r2, r4, r5 (=r5-2) |
| ! Scratch: r1, r3, r6, r7 |
| ! |
| ! We could do this with the four scratch registers, but if src |
| ! and dest hit the same cache line, this will thrash, so make |
| ! use of additional registers. |
| ! |
| ! We also need r0 as a temporary (for movca), so 'undo' the invariant: |
| ! r5: src (was r0+r5) |
| ! r1: dest (was r0) |
| ! this can be reversed at the end, so we don't need to save any extra |
| ! state. |
| ! |
| 1: mov.l r8, @-r15 ! 30 LS |
| add r0, r5 ! 49 EX |
| |
| mov.l r9, @-r15 ! 30 LS |
| mov r0, r1 ! 5 MT (latency=0) |
| |
| mov.l r10, @-r15 ! 30 LS |
| add #-0x1e, r5 ! 50 EX |
| |
| mov.l r11, @-r15 ! 30 LS |
| |
| mov.l r12, @-r15 ! 30 LS |
| |
| ! 17 cycles, 32 bytes per iteration |
| #ifdef CONFIG_CPU_LITTLE_ENDIAN |
| 2: mov.w @r5+, r0 ! 14 LS (latency=2) ..JI |
| add #-0x20, r1 ! 50 EX |
| |
| mov.l @r5+, r3 ! 15 LS (latency=2) NMLK |
| |
| mov.l @r5+, r6 ! 15 LS (latency=2) RQPO |
| shll16 r0 ! 103 EX JI.. |
| |
| mov.l @r5+, r7 ! 15 LS (latency=2) |
| xtrct r3, r0 ! 48 EX LKJI |
| |
| mov.l @r5+, r8 ! 15 LS (latency=2) |
| xtrct r6, r3 ! 48 EX PONM |
| |
| mov.l @r5+, r9 ! 15 LS (latency=2) |
| xtrct r7, r6 ! 48 EX |
| |
| mov.l @r5+, r10 ! 15 LS (latency=2) |
| xtrct r8, r7 ! 48 EX |
| |
| mov.l @r5+, r11 ! 15 LS (latency=2) |
| xtrct r9, r8 ! 48 EX |
| |
| mov.w @r5+, r12 ! 15 LS (latency=2) |
| xtrct r10, r9 ! 48 EX |
| |
| movca.l r0,@r1 ! 40 LS (latency=3-7) |
| xtrct r11, r10 ! 48 EX |
| |
| mov.l r3, @(0x04,r1) ! 33 LS |
| xtrct r12, r11 ! 48 EX |
| |
| mov.l r6, @(0x08,r1) ! 33 LS |
| |
| mov.l r7, @(0x0c,r1) ! 33 LS |
| |
| mov.l r8, @(0x10,r1) ! 33 LS |
| add #-0x40, r5 ! 50 EX |
| |
| mov.l r9, @(0x14,r1) ! 33 LS |
| cmp/eq r2,r1 ! 54 MT |
| |
| mov.l r10, @(0x18,r1) ! 33 LS |
| bf/s 2b ! 109 BR |
| |
| mov.l r11, @(0x1c,r1) ! 33 LS |
| #else |
| 2: mov.w @(0x1e,r5), r0 ! 17 LS (latency=2) |
| add #-2, r5 ! 50 EX |
| |
| mov.l @(0x1c,r5), r3 ! 18 LS (latency=2) |
| add #-4, r1 ! 50 EX |
| |
| mov.l @(0x18,r5), r6 ! 18 LS (latency=2) |
| shll16 r0 ! 103 EX |
| |
| mov.l @(0x14,r5), r7 ! 18 LS (latency=2) |
| xtrct r3, r0 ! 48 EX |
| |
| mov.l @(0x10,r5), r8 ! 18 LS (latency=2) |
| xtrct r6, r3 ! 48 EX |
| |
| mov.l @(0x0c,r5), r9 ! 18 LS (latency=2) |
| xtrct r7, r6 ! 48 EX |
| |
| mov.l @(0x08,r5), r10 ! 18 LS (latency=2) |
| xtrct r8, r7 ! 48 EX |
| |
| mov.l @(0x04,r5), r11 ! 18 LS (latency=2) |
| xtrct r9, r8 ! 48 EX |
| |
| mov.l @(0x00,r5), r12 ! 18 LS (latency=2) |
| xtrct r10, r9 ! 48 EX |
| |
| movca.l r0,@r1 ! 40 LS (latency=3-7) |
| add #-0x1c, r1 ! 50 EX |
| |
| mov.l r3, @(0x18,r1) ! 33 LS |
| xtrct r11, r10 ! 48 EX |
| |
| mov.l r6, @(0x14,r1) ! 33 LS |
| xtrct r12, r11 ! 48 EX |
| |
| mov.l r7, @(0x10,r1) ! 33 LS |
| |
| mov.l r8, @(0x0c,r1) ! 33 LS |
| add #-0x1e, r5 ! 50 EX |
| |
| mov.l r9, @(0x08,r1) ! 33 LS |
| cmp/eq r2,r1 ! 54 MT |
| |
| mov.l r10, @(0x04,r1) ! 33 LS |
| bf/s 2b ! 109 BR |
| |
| mov.l r11, @(0x00,r1) ! 33 LS |
| #endif |
| |
| mov.l @r15+, r12 |
| mov r1, r0 ! 5 MT (latency=0) |
| |
| mov.l @r15+, r11 ! 15 LS |
| sub r1, r5 ! 75 EX |
| |
| mov.l @r15+, r10 ! 15 LS |
| cmp/eq r4, r0 ! 54 MT |
| |
| bf/s 1f ! 109 BR |
| mov.l @r15+, r9 ! 15 LS |
| |
| rts |
| 1: mov.l @r15+, r8 ! 15 LS |
| |
| add #0x1e, r5 ! 50 EX |
| |
| ! Finish off a short word at a time |
| ! r5 must be invariant - 2 |
| 10: mov r4,r2 ! 5 MT (latency=0) |
| add #1,r2 ! 50 EX |
| |
| cmp/hi r2, r0 ! 57 MT |
| bf/s 1f ! 109 BR |
| |
| add #2, r2 ! 50 EX |
| |
| 3: mov.w @(r0,r5),r1 ! 20 LS |
| cmp/hi r2,r0 ! 57 MT |
| |
| bt/s 3b ! 109 BR |
| |
| mov.w r1,@-r0 ! 29 LS |
| 1: |
| |
| ! |
| ! Finally, copy the last byte if necessary |
| cmp/eq r4,r0 ! 54 MT |
| bt/s 9b |
| add #1,r5 |
| mov.b @(r0,r5),r1 |
| rts |
| mov.b r1,@-r0 |
| |