1/* a-memcpy.s -- memcpy, optimised for m68k asm
2 *
3 * Copyright (c) 2007 mocom software GmbH & Co KG)
4 *
5 * The authors hereby grant permission to use, copy, modify, distribute,
6 * and license this software and its documentation for any purpose, provided
7 * that existing copyright notices are retained in all copies and that this
8 * notice is included verbatim in any distributions. No written agreement,
9 * license, or royalty fee is required for any of the authorized uses.
10 * Modifications to this software may be copyrighted by their authors
11 * and need not follow the licensing terms described here, provided that
12 * the new terms are clearly indicated on the first page of each file where
13 * they apply.
14 */
15
16#include "m68kasm.h"
17
18#if defined (__mcoldfire__) || defined (__mc68020__) || defined (__mc68030__) || defined (__mc68040__) || defined (__mc68060__)
19# define MISALIGNED_OK 1
20#else
21# define MISALIGNED_OK 0
22#endif
23
24	.text
25	.align	4
26
27	.globl	SYM(memcpy)
28	.type	SYM(memcpy), @function
29
30/*   memcpy, optimised
31 *
32 *   strategy:
33 *       - no argument testing (the original memcpy from the GNU lib does
34 *         no checking either)
35 *       - make sure the destination pointer (the write pointer) is long word
36 *         aligned. This is the best you can do, because writing to unaligned
37 *         addresses can be the most costfull thing you could do.
38 *       - Once you have figured that out, we do a little loop unrolling
39 *         to further improve speed.
40 */
41
42SYM(memcpy):
43	move.l	4(sp),a0	| dest ptr
44	move.l	8(sp),a1	| src ptr
45	move.l	12(sp),d1	| len
46	cmp.l	#8,d1		| if fewer than 8 bytes to transfer,
47	blo	.Lresidue	| do not optimise
48
49#if !MISALIGNED_OK
50	/* Goto .Lresidue if either dest or src is not 4-byte aligned */
51	move.l	a0,d0
52	and.l	#3,d0
53	bne	.Lresidue
54	move.l	a1,d0
55	and.l	#3,d0
56	bne	.Lresidue
57#else /* MISALIGNED_OK */
58	/* align dest */
59	move.l	a0,d0		| copy of dest
60	neg.l	d0
61	and.l	#3,d0		| look for the lower two only
62	beq	2f		| is aligned?
63	sub.l	d0,d1
64	lsr.l	#1,d0		| word align needed?
65	bcc	1f
66	move.b	(a1)+,(a0)+
671:
68	lsr.l	#1,d0		| long align needed?
69	bcc	2f
70	move.w	(a1)+,(a0)+
712:
72#endif /* !MISALIGNED_OK */
73
74	/* long word transfers */
75	move.l	d1,d0
76	and.l	#3,d1		| byte residue
77	lsr.l	#3,d0
78	bcc	1f		| carry set for 4-byte residue
79	move.l	(a1)+,(a0)+
801:
81	lsr.l	#1,d0		| number of 16-byte transfers
82	bcc	.Lcopy 		| carry set for 8-byte residue
83	bra	.Lcopy8
84
851:
86	move.l	(a1)+,(a0)+
87	move.l	(a1)+,(a0)+
88.Lcopy8:
89	move.l	(a1)+,(a0)+
90	move.l	(a1)+,(a0)+
91.Lcopy:
92#if !defined (__mcoldfire__)
93	dbra	d0,1b
94	sub.l	#0x10000,d0
95#else
96	subq.l	#1,d0
97#endif
98	bpl	1b
99	bra	.Lresidue
100
1011:
102	move.b	(a1)+,(a0)+	| move residue bytes
103
104.Lresidue:
105#if !defined (__mcoldfire__)
106	dbra	d1,1b		| loop until done
107#else
108	subq.l	#1,d1
109	bpl	1b
110#endif
111	move.l	4(sp),a0	| return value
112	move.l	a0,d0		| in both a0 and d0
113	rts
114	.size	SYM(memcpy), . - SYM(memcpy)
115
116#if defined(__linux__) && defined(__ELF__)
117	.section .note.GNU-stack,"",%progbits
118#endif
119