! Copyright (C) 2008-2012 Imagination Technologies Ltd. | |

.text | |

.global _memmove | |

.type _memmove,function | |

! D1Ar1 dst | |

! D0Ar2 src | |

! D1Ar3 cnt | |

! D0Re0 dst | |

_memmove: | |

CMP D1Ar3, #0 | |

MOV D0Re0, D1Ar1 | |

BZ $LEND2 | |

MSETL [A0StP], D0.5, D0.6, D0.7 | |

MOV D1Ar5, D0Ar2 | |

CMP D1Ar1, D1Ar5 | |

BLT $Lforwards_copy | |

SUB D0Ar4, D1Ar1, D1Ar3 | |

ADD D0Ar4, D0Ar4, #1 | |

CMP D0Ar2, D0Ar4 | |

BLT $Lforwards_copy | |

! should copy backwards | |

MOV D1Re0, D0Ar2 | |

! adjust pointer to the end of mem | |

ADD D0Ar2, D1Re0, D1Ar3 | |

ADD D1Ar1, D1Ar1, D1Ar3 | |

MOV A1.2, D0Ar2 | |

MOV A0.2, D1Ar1 | |

CMP D1Ar3, #8 | |

BLT $Lbbyte_loop | |

MOV D0Ar4, D0Ar2 | |

MOV D1Ar5, D1Ar1 | |

! test 8 byte alignment | |

ANDS D1Ar5, D1Ar5, #7 | |

BNE $Lbdest_unaligned | |

ANDS D0Ar4, D0Ar4, #7 | |

BNE $Lbsrc_unaligned | |

LSR D1Ar5, D1Ar3, #3 | |

$Lbaligned_loop: | |

GETL D0Re0, D1Re0, [--A1.2] | |

SETL [--A0.2], D0Re0, D1Re0 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lbaligned_loop | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lbbyte_loop_exit | |

$Lbbyte_loop: | |

GETB D1Re0, [--A1.2] | |

SETB [--A0.2], D1Re0 | |

SUBS D1Ar3, D1Ar3, #1 | |

BNE $Lbbyte_loop | |

$Lbbyte_loop_exit: | |

MOV D0Re0, A0.2 | |

$LEND: | |

SUB A0.2, A0StP, #24 | |

MGETL D0.5, D0.6, D0.7, [A0.2] | |

SUB A0StP, A0StP, #24 | |

$LEND2: | |

MOV PC, D1RtP | |

$Lbdest_unaligned: | |

GETB D0Re0, [--A1.2] | |

SETB [--A0.2], D0Re0 | |

SUBS D1Ar5, D1Ar5, #1 | |

SUB D1Ar3, D1Ar3, #1 | |

BNE $Lbdest_unaligned | |

CMP D1Ar3, #8 | |

BLT $Lbbyte_loop | |

$Lbsrc_unaligned: | |

LSR D1Ar5, D1Ar3, #3 | |

! adjust A1.2 | |

MOV D0Ar4, A1.2 | |

! save original address | |

MOV D0Ar6, A1.2 | |

ADD D0Ar4, D0Ar4, #7 | |

ANDMB D0Ar4, D0Ar4, #0xfff8 | |

! new address is the 8-byte aligned one above the original | |

MOV A1.2, D0Ar4 | |

! A0.2 dst 64-bit is aligned | |

! measure the gap size | |

SUB D0Ar6, D0Ar4, D0Ar6 | |

MOVS D0Ar4, D0Ar6 | |

! keep this information for the later adjustment | |

! both aligned | |

BZ $Lbaligned_loop | |

! prefetch | |

GETL D0Re0, D1Re0, [--A1.2] | |

CMP D0Ar6, #4 | |

BLT $Lbunaligned_1_2_3 | |

! 32-bit aligned | |

BZ $Lbaligned_4 | |

SUB D0Ar6, D0Ar6, #4 | |

! D1.6 stores the gap size in bits | |

MULW D1.6, D0Ar6, #8 | |

MOV D0.6, #32 | |

! D0.6 stores the complement of the gap size | |

SUB D0.6, D0.6, D1.6 | |

$Lbunaligned_5_6_7: | |

GETL D0.7, D1.7, [--A1.2] | |

! form 64-bit data in D0Re0, D1Re0 | |

MOV D1Re0, D0Re0 | |

! D1Re0 << gap-size | |

LSL D1Re0, D1Re0, D1.6 | |

MOV D0Re0, D1.7 | |

! D0Re0 >> complement | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D1.5, D0Re0 | |

! combine the both | |

ADD D1Re0, D1Re0, D1.5 | |

MOV D1.5, D1.7 | |

LSL D1.5, D1.5, D1.6 | |

MOV D0Re0, D0.7 | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D0.5, D1.5 | |

ADD D0Re0, D0Re0, D0.5 | |

SETL [--A0.2], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lbunaligned_5_6_7 | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lbbyte_loop_exit | |

! Adjust A1.2 | |

! A1.2 <- A1.2 +8 - gapsize | |

ADD A1.2, A1.2, #8 | |

SUB A1.2, A1.2, D0Ar4 | |

B $Lbbyte_loop | |

$Lbunaligned_1_2_3: | |

MULW D1.6, D0Ar6, #8 | |

MOV D0.6, #32 | |

SUB D0.6, D0.6, D1.6 | |

$Lbunaligned_1_2_3_loop: | |

GETL D0.7, D1.7, [--A1.2] | |

! form 64-bit data in D0Re0, D1Re0 | |

LSL D1Re0, D1Re0, D1.6 | |

! save D0Re0 for later use | |

MOV D0.5, D0Re0 | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D1.5, D0Re0 | |

ADD D1Re0, D1Re0, D1.5 | |

! orignal data in D0Re0 | |

MOV D1.5, D0.5 | |

LSL D1.5, D1.5, D1.6 | |

MOV D0Re0, D1.7 | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D0.5, D1.5 | |

ADD D0Re0, D0Re0, D0.5 | |

SETL [--A0.2], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lbunaligned_1_2_3_loop | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lbbyte_loop_exit | |

! Adjust A1.2 | |

ADD A1.2, A1.2, #8 | |

SUB A1.2, A1.2, D0Ar4 | |

B $Lbbyte_loop | |

$Lbaligned_4: | |

GETL D0.7, D1.7, [--A1.2] | |

MOV D1Re0, D0Re0 | |

MOV D0Re0, D1.7 | |

SETL [--A0.2], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lbaligned_4 | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lbbyte_loop_exit | |

! Adjust A1.2 | |

ADD A1.2, A1.2, #8 | |

SUB A1.2, A1.2, D0Ar4 | |

B $Lbbyte_loop | |

$Lforwards_copy: | |

MOV A1.2, D0Ar2 | |

MOV A0.2, D1Ar1 | |

CMP D1Ar3, #8 | |

BLT $Lfbyte_loop | |

MOV D0Ar4, D0Ar2 | |

MOV D1Ar5, D1Ar1 | |

ANDS D1Ar5, D1Ar5, #7 | |

BNE $Lfdest_unaligned | |

ANDS D0Ar4, D0Ar4, #7 | |

BNE $Lfsrc_unaligned | |

LSR D1Ar5, D1Ar3, #3 | |

$Lfaligned_loop: | |

GETL D0Re0, D1Re0, [A1.2++] | |

SUBS D1Ar5, D1Ar5, #1 | |

SETL [A0.2++], D0Re0, D1Re0 | |

BNE $Lfaligned_loop | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lfbyte_loop_exit | |

$Lfbyte_loop: | |

GETB D1Re0, [A1.2++] | |

SETB [A0.2++], D1Re0 | |

SUBS D1Ar3, D1Ar3, #1 | |

BNE $Lfbyte_loop | |

$Lfbyte_loop_exit: | |

MOV D0Re0, D1Ar1 | |

B $LEND | |

$Lfdest_unaligned: | |

GETB D0Re0, [A1.2++] | |

ADD D1Ar5, D1Ar5, #1 | |

SUB D1Ar3, D1Ar3, #1 | |

SETB [A0.2++], D0Re0 | |

CMP D1Ar5, #8 | |

BNE $Lfdest_unaligned | |

CMP D1Ar3, #8 | |

BLT $Lfbyte_loop | |

$Lfsrc_unaligned: | |

! adjust A1.2 | |

LSR D1Ar5, D1Ar3, #3 | |

MOV D0Ar4, A1.2 | |

MOV D0Ar6, A1.2 | |

ANDMB D0Ar4, D0Ar4, #0xfff8 | |

MOV A1.2, D0Ar4 | |

! A0.2 dst 64-bit is aligned | |

SUB D0Ar6, D0Ar6, D0Ar4 | |

! keep the information for the later adjustment | |

MOVS D0Ar4, D0Ar6 | |

! both aligned | |

BZ $Lfaligned_loop | |

! prefetch | |

GETL D0Re0, D1Re0, [A1.2] | |

CMP D0Ar6, #4 | |

BLT $Lfunaligned_1_2_3 | |

BZ $Lfaligned_4 | |

SUB D0Ar6, D0Ar6, #4 | |

MULW D0.6, D0Ar6, #8 | |

MOV D1.6, #32 | |

SUB D1.6, D1.6, D0.6 | |

$Lfunaligned_5_6_7: | |

GETL D0.7, D1.7, [++A1.2] | |

! form 64-bit data in D0Re0, D1Re0 | |

MOV D0Re0, D1Re0 | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D1Re0, D0.7 | |

LSL D1Re0, D1Re0, D1.6 | |

MOV D0.5, D1Re0 | |

ADD D0Re0, D0Re0, D0.5 | |

MOV D0.5, D0.7 | |

LSR D0.5, D0.5, D0.6 | |

MOV D1Re0, D1.7 | |

LSL D1Re0, D1Re0, D1.6 | |

MOV D1.5, D0.5 | |

ADD D1Re0, D1Re0, D1.5 | |

SETL [A0.2++], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lfunaligned_5_6_7 | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lfbyte_loop_exit | |

! Adjust A1.2 | |

ADD A1.2, A1.2, D0Ar4 | |

B $Lfbyte_loop | |

$Lfunaligned_1_2_3: | |

MULW D0.6, D0Ar6, #8 | |

MOV D1.6, #32 | |

SUB D1.6, D1.6, D0.6 | |

$Lfunaligned_1_2_3_loop: | |

GETL D0.7, D1.7, [++A1.2] | |

! form 64-bit data in D0Re0, D1Re0 | |

LSR D0Re0, D0Re0, D0.6 | |

MOV D1.5, D1Re0 | |

LSL D1Re0, D1Re0, D1.6 | |

MOV D0.5, D1Re0 | |

ADD D0Re0, D0Re0, D0.5 | |

MOV D0.5, D1.5 | |

LSR D0.5, D0.5, D0.6 | |

MOV D1Re0, D0.7 | |

LSL D1Re0, D1Re0, D1.6 | |

MOV D1.5, D0.5 | |

ADD D1Re0, D1Re0, D1.5 | |

SETL [A0.2++], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lfunaligned_1_2_3_loop | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lfbyte_loop_exit | |

! Adjust A1.2 | |

ADD A1.2, A1.2, D0Ar4 | |

B $Lfbyte_loop | |

$Lfaligned_4: | |

GETL D0.7, D1.7, [++A1.2] | |

MOV D0Re0, D1Re0 | |

MOV D1Re0, D0.7 | |

SETL [A0.2++], D0Re0, D1Re0 | |

MOV D0Re0, D0.7 | |

MOV D1Re0, D1.7 | |

SUBS D1Ar5, D1Ar5, #1 | |

BNE $Lfaligned_4 | |

ANDS D1Ar3, D1Ar3, #7 | |

BZ $Lfbyte_loop_exit | |

! Adjust A1.2 | |

ADD A1.2, A1.2, D0Ar4 | |

B $Lfbyte_loop | |

.size _memmove,.-_memmove |