/* SPDX-License-Identifier: GPL-2.0 */1/*2* arch/alpha/lib/ev6-memcpy.S3* 21264 version by Rick Gorton <[email protected]>4*5* Reasonably optimized memcpy() routine for the Alpha 212646*7* - memory accessed as aligned quadwords only8* - uses bcmpge to compare 8 bytes in parallel9*10* Much of the information about 21264 scheduling/coding comes from:11* Compiler Writer's Guide for the Alpha 2126412* abbreviated as 'CWG' in other comments here13* ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html14* Scheduling notation:15* E - either cluster16* U - upper subcluster; U0 - subcluster U0; U1 - subcluster U117* L - lower subcluster; L0 - subcluster L0; L1 - subcluster L118*19* Temp usage notes:20* $1,$2, - scratch21*/22#include <linux/export.h>23.set noreorder24.set noat2526.align 427.globl memcpy28.ent memcpy29memcpy:30.frame $30,0,$26,031.prologue 03233mov $16, $0 # E : copy dest to return34ble $18, $nomoredata # U : done with the copy?35xor $16, $17, $1 # E : are source and dest alignments the same?36and $1, 7, $1 # E : are they the same mod 8?3738bne $1, $misaligned # U : Nope - gotta do this the slow way39/* source and dest are same mod 8 address */40and $16, 7, $1 # E : Are both 0mod8?41beq $1, $both_0mod8 # U : Yes42nop # E :4344/*45* source and dest are same misalignment. move a byte at a time46* until a 0mod8 alignment for both is reached.47* At least one byte more to move48*/4950$head_align:51ldbu $1, 0($17) # L : grab a byte52subq $18, 1, $18 # E : count--53addq $17, 1, $17 # E : src++54stb $1, 0($16) # L :55addq $16, 1, $16 # E : dest++56and $16, 7, $1 # E : Are we at 0mod8 yet?57ble $18, $nomoredata # U : done with the copy?58bne $1, $head_align # U :5960$both_0mod8:61cmple $18, 127, $1 # E : Can we unroll the loop?62bne $1, $no_unroll # U :63and $16, 63, $1 # E : get mod64 alignment64beq $1, $do_unroll # U : no single quads to fiddle6566$single_head_quad:67ldq $1, 0($17) # L : get 8 bytes68subq $18, 8, $18 # E : count -= 869addq $17, 8, $17 # E : src += 870nop # E :7172stq $1, 0($16) # L : store73addq $16, 8, $16 # E : dest += 874and $16, 63, $1 # E : get mod64 alignment75bne $1, $single_head_quad # U : still not fully aligned7677$do_unroll:78addq $16, 64, $7 # E : Initial (+1 trip) wh64 address79cmple $18, 127, $1 # E : Can we go through the unrolled loop?80bne $1, $tail_quads # U : Nope81nop # E :8283$unroll_body:84wh64 ($7) # L1 : memory subsystem hint: 64 bytes at85# ($7) are about to be over-written86ldq $6, 0($17) # L0 : bytes 0..787nop # E :88nop # E :8990ldq $4, 8($17) # L : bytes 8..1591ldq $5, 16($17) # L : bytes 16..2392addq $7, 64, $7 # E : Update next wh64 address93nop # E :9495ldq $3, 24($17) # L : bytes 24..3196addq $16, 64, $1 # E : fallback value for wh6497nop # E :98nop # E :99100addq $17, 32, $17 # E : src += 32 bytes101stq $6, 0($16) # L : bytes 0..7102nop # E :103nop # E :104105stq $4, 8($16) # L : bytes 8..15106stq $5, 16($16) # L : bytes 16..23107subq $18, 192, $2 # E : At least two more trips to go?108nop # E :109110stq $3, 24($16) # L : bytes 24..31111addq $16, 32, $16 # E : dest += 32 bytes112nop # E :113nop # E :114115ldq $6, 0($17) # L : bytes 0..7116ldq $4, 8($17) # L : bytes 8..15117cmovlt $2, $1, $7 # E : Latency 2, extra map slot - Use118# fallback wh64 address if < 2 more trips119nop # E :120121ldq $5, 16($17) # L : bytes 16..23122ldq $3, 24($17) # L : bytes 24..31123addq $16, 32, $16 # E : dest += 32124subq $18, 64, $18 # E : count -= 64125126addq $17, 32, $17 # E : src += 32127stq $6, -32($16) # L : bytes 0..7128stq $4, -24($16) # L : bytes 8..15129cmple $18, 63, $1 # E : At least one more trip?130131stq $5, -16($16) # L : bytes 16..23132stq $3, -8($16) # L : bytes 24..31133nop # E :134beq $1, $unroll_body135136$tail_quads:137$no_unroll:138.align 4139subq $18, 8, $18 # E : At least a quad left?140blt $18, $less_than_8 # U : Nope141nop # E :142nop # E :143144$move_a_quad:145ldq $1, 0($17) # L : fetch 8146subq $18, 8, $18 # E : count -= 8147addq $17, 8, $17 # E : src += 8148nop # E :149150stq $1, 0($16) # L : store 8151addq $16, 8, $16 # E : dest += 8152bge $18, $move_a_quad # U :153nop # E :154155$less_than_8:156.align 4157addq $18, 8, $18 # E : add back for trailing bytes158ble $18, $nomoredata # U : All-done159nop # E :160nop # E :161162/* Trailing bytes */163$tail_bytes:164subq $18, 1, $18 # E : count--165ldbu $1, 0($17) # L : fetch a byte166addq $17, 1, $17 # E : src++167nop # E :168169stb $1, 0($16) # L : store a byte170addq $16, 1, $16 # E : dest++171bgt $18, $tail_bytes # U : more to be done?172nop # E :173174/* branching to exit takes 3 extra cycles, so replicate exit here */175ret $31, ($26), 1 # L0 :176nop # E :177nop # E :178nop # E :179180$misaligned:181mov $0, $4 # E : dest temp182and $0, 7, $1 # E : dest alignment mod8183beq $1, $dest_0mod8 # U : life doesnt totally suck184nop185186$aligndest:187ble $18, $nomoredata # U :188ldbu $1, 0($17) # L : fetch a byte189subq $18, 1, $18 # E : count--190addq $17, 1, $17 # E : src++191192stb $1, 0($4) # L : store it193addq $4, 1, $4 # E : dest++194and $4, 7, $1 # E : dest 0mod8 yet?195bne $1, $aligndest # U : go until we are aligned.196197/* Source has unknown alignment, but dest is known to be 0mod8 */198$dest_0mod8:199subq $18, 8, $18 # E : At least a quad left?200blt $18, $misalign_tail # U : Nope201ldq_u $3, 0($17) # L : seed (rotating load) of 8 bytes202nop # E :203204$mis_quad:205ldq_u $16, 8($17) # L : Fetch next 8206extql $3, $17, $3 # U : masking207extqh $16, $17, $1 # U : masking208bis $3, $1, $1 # E : merged bytes to store209210subq $18, 8, $18 # E : count -= 8211addq $17, 8, $17 # E : src += 8212stq $1, 0($4) # L : store 8 (aligned)213mov $16, $3 # E : "rotate" source data214215addq $4, 8, $4 # E : dest += 8216bge $18, $mis_quad # U : More quads to move217nop218nop219220$misalign_tail:221addq $18, 8, $18 # E : account for tail stuff222ble $18, $nomoredata # U :223nop224nop225226$misalign_byte:227ldbu $1, 0($17) # L : fetch 1228subq $18, 1, $18 # E : count--229addq $17, 1, $17 # E : src++230nop # E :231232stb $1, 0($4) # L : store233addq $4, 1, $4 # E : dest++234bgt $18, $misalign_byte # U : more to go?235nop236237238$nomoredata:239ret $31, ($26), 1 # L0 :240nop # E :241nop # E :242nop # E :243244.end memcpy245EXPORT_SYMBOL(memcpy)246247/* For backwards module compatibility. */248__memcpy = memcpy249.globl __memcpy250251252