Factor out some drawing code.
[kugel-rb.git] / firmware / target / coldfire / memcpy-coldfire.S
blob9762e31e0273a5e97eee42c3061cc672848cda38
1 /***************************************************************************
2  *             __________               __   ___.
3  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
4  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
5  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
6  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
7  *                     \/            \/     \/    \/            \/
8  * $Id$
9  *
10  * Copyright (C) 2004-2005 by Jens Arnold
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18  * KIND, either express or implied.
19  *
20  ****************************************************************************/
21 #include "config.h"
23     .section    .icode,"ax",@progbits
25 #define FULLSPEED /* use burst writing for word aligned destinations */
26     .align  2
27     .global memcpy
28     .global __memcpy_fwd_entry
29     .type   memcpy,@function
31 /* Copies <length> bytes of data in memory from <source> to <dest>
32  * This version is optimized for speed
33  *
34  * arguments:
35  *  (4,%sp)  - destination address
36  *  (8,%sp)  - source address
37  *  (12,%sp) - length
38  *
39  * return value:
40  *  %d0 - destination address (like ANSI version)
41  *
42  * register usage:
43  *  %a0 - current source address
44  *  %a1 - current dest address
45  *  %a2 - source end address (in line-copy loops)
46  *  %d0 - data / scratch
47  *  %d1 - source end address (byte and longword copy) / data / scratch
48  *  %d2 - data / scratch
49  *  %d3..%d7 - data
50  *
51  * For maximum speed this routine reads and writes whole lines using burst
52  * move (movem.l) where possible. For byte aligned destinations (long+1 and
53  * long+3) it writes longwords only. Same goes for word aligned destinations
54  * if FULLSPEED is undefined.
55  */
56 memcpy:
57     move.l  (4,%sp),%a1     /* Destination */
58     move.l  (8,%sp),%a0     /* Source */
59     move.l  (12,%sp),%d1    /* Length */
61 __memcpy_fwd_entry:
62     add.l   %a0,%d1         /* %d1 = source end */
64     move.l  %a0,%d0
65     addq.l  #7,%d0
66     and.l   #0xFFFFFFFC,%d0 /* %d0 = first source long bound + 4 */
67     cmp.l   %d0,%d1         /* at least one aligned longword to copy? */
68     blo.w   .bytes2_start   /* no, jump directly to trailing byte loop */
69     
70     subq.l  #4,%d0          /* %d0 = first source long bound */
71     cmp.l   %a0,%d0         /* any bytes to copy? */
72     jls     .bytes1_end     /* no: skip byte loop */
74     /* leading byte loop: copies 0..3 bytes */
75 .bytes1_loop:
76     move.b  (%a0)+,(%a1)+   /* copy byte */
77     cmp.l   %a0,%d0         /* runs %a0 up to first long bound */
78     jhi     .bytes1_loop
80 .bytes1_end:
81     moveq.l #31,%d0
82     add.l   %a0,%d0
83     and.l   #0xFFFFFFF0,%d0 /* %d0 = first source line bound + 16 */
84     cmp.l   %d0,%d1         /* at least one aligned line to copy? */
85     blo.w   .long_start     /* no: jump to longword copy loop */
86     
87     lea.l   (-28,%sp),%sp   /* free up some registers */
88     movem.l %d2-%d7/%a2,(%sp)
90     moveq.l #16,%d2
91     sub.l   %d2,%d0         /* %d0 = first source line bound */
92     move.l  %d1,%a2         /* %a2 = end address */
93     lea.l   (-15,%a2),%a2   /* adjust end address for loops doing 16 bytes/ pass */
94     move.l  %a1,%d1
95     moveq.l #3,%d2          /* mask */
96     and.l   %d2,%d1
97     jmp.l   (2,%pc,%d1.l*4) /* switch (dest_addr & 3) */
98     bra.w   .lines_do0_start
99     bra.w   .lines_do1_start
100     bra.w   .lines_do2_start
101  /* bra.w   .lines_do3_start   implicit */
103     /* byte aligned destination (long + 3): use line burst reads in main loop */
104 .lines_do3_start:
105     moveq.l #24,%d1         /* shift count for shifting by 3 bytes */
106     cmp.l   %a0,%d0         /* any leading longwords? */
107     jhi     .lines_do3_head_start  /* yes: leading longword copy */
109     movem.l (%a0),%d4-%d7   /* load first line */
110     lea.l   (16,%a0),%a0
111     move.l  %d4,%d2
112     lsr.l   %d1,%d2         /* get high byte of first longword */
113     move.b  %d2,(%a1)+      /* store byte */
114     jra     .lines_do3_entry       /* jump into main loop */
115     
116 .lines_do3_head_start:
117     move.l  (%a0)+,%d7      /* load first longword */
118     move.l  %d7,%d2
119     lsr.l   %d1,%d2         /* get high byte */
120     move.b  %d2,(%a1)+      /* store byte */
121     jra     .lines_do3_head_entry  /* jump into leading longword loop */
123 .lines_do3_head_loop:
124     move.l  %d7,%d6         /* move old longword away */
125     move.l  (%a0)+,%d7      /* load new longword */
126     move.l  %d7,%d2
127     lsr.l   %d1,%d2         /* get high byte */
128     or.l    %d2,%d6         /* combine with old lower 3 bytes */
129     move.l  %d6,(%a1)+      /* store longword */
130 .lines_do3_head_entry:
131     lsl.l   #8,%d7          /* shift up lower 3 bytes */
132     cmp.l   %a0,%d0         /* runs %a0 up to first line bound */
133     jhi     .lines_do3_head_loop
135 .lines_do3_loop:
136     move.l  %d7,%d3         /* move last longword of old line away */
137     movem.l (%a0),%d4-%d7   /* load new line */
138     lea.l   (16,%a0),%a0
139     move.l  %d4,%d2
140     lsr.l   %d1,%d2         /* get high byte of 1st longword */
141     or.l    %d2,%d3         /* combine with old lower 3 bytes */
142     move.l  %d3,(%a1)+      /* store longword */
143 .lines_do3_entry:
144     lsl.l   #8,%d4          /* shift up lower 3 bytes */
145     move.l  %d5,%d2
146     lsr.l   %d1,%d2         /* get high byte of 2nd longword */
147     or.l    %d2,%d4         /* combine with 1st lower 3 bytes */
148     move.l  %d4,(%a1)+      /* store longword */
149     lsl.l   #8,%d5          /* shift up lower 3 bytes */
150     move.l  %d6,%d2
151     lsr.l   %d1,%d2         /* get high byte of 3rd longword */
152     or.l    %d2,%d5         /* combine with 2nd lower 3 bytes */
153     move.l  %d5,(%a1)+      /* store longword */
154     lsl.l   #8,%d6          /* shift up lower 3 bytes */
155     move.l  %d7,%d2
156     lsr.l   %d1,%d2         /* get high byte of 4th longword */
157     or.l    %d2,%d6         /* combine with 3rd lower 3 bytes */
158     move.l  %d6,(%a1)+      /* store longword */
159     lsl.l   #8,%d7          /* shift up lower 3 bytes */
160     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
161     jhi     .lines_do3_loop
163     lea.l   (12,%a2),%a2    /* readjust end address for doing longwords */
164     cmp.l   %a0,%a2         /* any trailing longwords? */
165     jls     .lines_do3_tail_end    /* no: just store last lower 3 bytes */
167 .lines_do3_tail_loop:
168     move.l  %d7,%d6         /* move old longword away */
169     move.l  (%a0)+,%d7      /* load new longword */
170     move.l  %d7,%d2
171     lsr.l   %d1,%d2         /* get high byte */
172     or.l    %d2,%d6         /* combine with old lower 3 bytes */
173     move.l  %d6,(%a1)+      /* store longword */
174     lsl.l   #8,%d7          /* shift up lower 3 bytes */
175     cmp.l   %a0,%a2         /* runs %a0 up to last long bound */
176     jhi     .lines_do3_tail_loop
178 .lines_do3_tail_end:
179     swap    %d7             /* get high word */
180     move.w  %d7,(%a1)+      /* store word */
181     lsr.l   %d1,%d7         /* get moved-up low byte */
182     move.b  %d7,(%a1)+      /* store byte */
183     jra     .lines_end
185     /* byte aligned destination (long + 1): use line burst reads in main loop */
186 .lines_do1_start:
187     moveq.l #24,%d1         /* shift count for shifting by 3 bytes */
188     cmp.l   %a0,%d0         /* any leading longwords? */
189     jhi     .lines_do1_head_start  /* yes: leading longword copy */
191     movem.l (%a0),%d4-%d7   /* load first line */
192     lea.l   (16,%a0),%a0
193     move.l  %d4,%d2         /* first longword, bytes 3210 */
194     lsr.l   #8,%d2          /* first longword, bytes .321 */
195     swap    %d2             /* first longword, bytes 21.3 */
196     move.b  %d2,(%a1)+      /* store byte */
197     swap    %d2             /* first longword, bytes .321 */
198     move.w  %d2,(%a1)+      /* store word */
199     jra     .lines_do1_entry
201 .lines_do1_head_start:
202     move.l  (%a0)+,%d7      /* load first longword */
203     move.l  %d7,%d2         /* first longword, bytes 3210 */
204     lsr.l   #8,%d2          /* first longword, bytes .321 */
205     swap    %d2             /* first longword, bytes 21.3 */
206     move.b  %d2,(%a1)+      /* store byte */
207     swap    %d2             /* first longword, bytes .321 */
208     move.w  %d2,(%a1)+      /* store word */
209     jra     .lines_do1_head_entry
211 .lines_do1_head_loop:
212     move.l  %d7,%d6         /* move old longword away */
213     move.l  (%a0)+,%d7      /* load new longword */
214     move.l  %d7,%d2
215     lsr.l   #8,%d2          /* get upper 3 bytes */
216     or.l    %d2,%d6         /* combine with old low byte */
217     move.l  %d6,(%a1)+      /* store longword */
218 .lines_do1_head_entry:
219     lsl.l   %d1,%d7         /* shift up low byte */
220     cmp.l   %a0,%d0         /* runs %a0 up to first line bound */
221     jhi     .lines_do1_head_loop
223 .lines_do1_loop:
224     move.l  %d7,%d3         /* move last longword of old line away */
225     movem.l (%a0),%d4-%d7   /* load new line */
226     lea.l   (16,%a0),%a0
227     move.l  %d4,%d2
228     lsr.l   #8,%d2          /* get upper 3 bytes of 1st longword */
229     or.l    %d2,%d3         /* combine with low byte of old longword */
230     move.l  %d3,(%a1)+      /* store longword */
231 .lines_do1_entry:
232     lsl.l   %d1,%d4         /* shift up low byte */
233     move.l  %d5,%d2
234     lsr.l   #8,%d2          /* get upper 3 bytes of 2nd longword */
235     or.l    %d2,%d4         /* combine with low byte of 1st longword */
236     move.l  %d4,(%a1)+      /* store longword */
237     lsl.l   %d1,%d5         /* shift up low byte */
238     move.l  %d6,%d2
239     lsr.l   #8,%d2          /* get upper 3 bytes of 3rd longword */
240     or.l    %d2,%d5         /* combine with low byte of 2nd longword */
241     move.l  %d5,(%a1)+      /* store longword */
242     lsl.l   %d1,%d6         /* shift up low byte */
243     move.l  %d7,%d2
244     lsr.l   #8,%d2          /* get upper 3 bytes of 4th longword */
245     or.l    %d2,%d6         /* combine with low byte of 4th longword */
246     move.l  %d6,(%a1)+      /* store longword */
247     lsl.l   %d1,%d7         /* shift up low byte */
248     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
249     jhi     .lines_do1_loop
250     
251     lea.l   (12,%a2),%a2    /* readjust end address for doing longwords */
252     cmp.l   %a0,%a2         /* any trailing longwords? */
253     jls     .lines_do1_tail_end    /* no: just store last low byte */
254     
255 .lines_do1_tail_loop:
256     move.l  %d7,%d6         /* move old longword away */
257     move.l  (%a0)+,%d7      /* load new longword */
258     move.l  %d7,%d2
259     lsr.l   #8,%d2          /* get upper 3 bytes */
260     or.l    %d2,%d6         /* combine with old low byte */
261     move.l  %d6,(%a1)+      /* store longword */
262     lsl.l   %d1,%d7         /* shift up low byte */
263     cmp.l   %a0,%a2         /* runs %a0 up to last long bound */
264     jhi     .lines_do1_tail_loop
266 .lines_do1_tail_end:
267     lsr.l   %d1,%d7         /* get shifted-up low byte */
268     move.b  %d7,(%a1)+      /* store byte */
269     jra     .lines_end
271     /* long aligned destination (line + 0/4/8/12): head */
272 .lines_do0_head_loop:
273     move.l  (%a0)+,(%a1)+   /* copy longword */
274 .lines_do0_start:
275     cmp.l   %a0,%d0         /* runs %a0 up to first line bound */
276     jhi     .lines_do0_head_loop
278 .lines_do0_head_end:
279     move.l  %a1,%d1
280     lsr.l   #2,%d1
281     moveq.l #3,%d0          /* mask */
282     and.l   %d0,%d1
283     moveq.l #16,%d0         /* address increment for one main loop pass */
284     jmp.l   (2,%pc,%d1.l*2) /* switch ((dest_addr >> 2) & 3) */
285     bra.b   .lines_lo0_start
286     bra.b   .lines_lo4_start
287     bra.b   .lines_lo8_start
288  /* bra.b   .lines_lo12_start   implicit */
290     /* long aligned destination (line + 12): use line bursts in the loop */
291 .lines_lo12_start:
292     movem.l (%a0),%d4-%d7   /* load first line */
293     add.l   %d0,%a0
294     move.l  %d4,(%a1)+      /* store 1st longword */
295     cmp.l   %a0,%a2         /* any full lines? */
296     jls     .lines_lo12_end /* no: skip main loop */
298 .lines_lo12_loop:
299     move.l  %d5,%d1         /* move last 3 longwords of old line away */
300     move.l  %d6,%d2
301     move.l  %d7,%d3
302     movem.l (%a0),%d4-%d7   /* load new line */
303     add.l   %d0,%a0
304     movem.l %d1-%d4,(%a1)   /* store line (3 old + 1 new longwords) */
305     add.l   %d0,%a1
306     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
307     jhi     .lines_lo12_loop
309     /* long aligned destination (line + 0/4/8/12): tail */
310 .lines_lo12_end:
311     move.l  %d5,(%a1)+      /* store 3rd last longword */
312 .lines_lo8_end:
313     move.l  %d6,(%a1)+      /* store 2nd last longword */
314 .lines_lo4_end:
315     move.l  %d7,(%a1)+      /* store last longword */
316 .lines_lo0_end:
317     lea.l   (12,%a2),%a2    /* readjust end address for doing longwords */
318     cmp.l   %a0,%a2         /* any trailing longwords? */
319     jls     .lines_end      /* no: get outta here */
321 .lines_do0_tail_loop:
322     move.l  (%a0)+,(%a1)+   /* copy longword */
323     cmp.l   %a0,%a2         /* runs %a0 up to last long bound */
324     jhi     .lines_do0_tail_loop
326     jra     .lines_end 
327     
328     /* line aligned destination: use line bursts in the loop */
329 .lines_lo0_start:
330 .lines_lo0_loop:
331     movem.l (%a0),%d4-%d7   /* load line */
332     add.l   %d0,%a0
333     movem.l %d4-%d7,(%a1)   /* store line */
334     add.l   %d0,%a1
335     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
336     jhi     .lines_lo0_loop
338     jra     .lines_lo0_end  /* handle trailing longwords */
340     /* long aligned destination (line + 4): use line bursts in the loop */
341 .lines_lo4_start:
342     movem.l (%a0),%d4-%d7   /* load first line */
343     add.l   %d0,%a0
344     move.l  %d4,(%a1)+      /* store 1st longword */
345     move.l  %d5,(%a1)+      /* store 2nd longword */
346     move.l  %d6,(%a1)+      /* store 3rd longword */
347     cmp.l   %a0,%a2         /* any full lines? */
348     jls     .lines_lo4_end  /* no: skip main loop */
350 .lines_lo4_loop:
351     move.l  %d7,%d3         /* move last longword of old line away */
352     movem.l (%a0),%d4-%d7   /* load new line */
353     add.l   %d0,%a0
354     movem.l %d3-%d6,(%a1)   /* store line (1 old + 3 new longwords) */
355     add.l   %d0,%a1
356     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
357     jhi     .lines_lo4_loop
359     jra     .lines_lo4_end  /* handle trailing longwords */
361     /* long aligned destination (line + 8): use line bursts in the loop */
362 .lines_lo8_start:
363     movem.l (%a0),%d4-%d7   /* load first line */
364     add.l   %d0,%a0
365     move.l  %d4,(%a1)+      /* store 1st longword */
366     move.l  %d5,(%a1)+      /* store 2nd longword */
367     cmp.l   %a0,%a2
368     jls     .lines_lo8_end
370 .lines_lo8_loop:
371     move.l  %d6,%d2         /* move last 2 longwords of old line away */
372     move.l  %d7,%d3
373     movem.l (%a0),%d4-%d7   /* load new line */
374     add.l   %d0,%a0
375     movem.l %d2-%d5,(%a1)   /* store line (2 old + 2 new longwords) */
376     add.l   %d0,%a1
377     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
378     jhi     .lines_lo8_loop
380     jra     .lines_lo8_end  /* handle trailing longwords */
382 #ifdef FULLSPEED
384     /* word aligned destination (line + 2/6/10/14): head */
385 .lines_do2_start:
386     cmp.l   %a0,%d0         /* any leading longwords? */
387     jls     .lines_do2_selector    /* no: jump to mainloop selector */
389     move.l  (%a0)+,%d7      /* load first longword */
390     swap    %d7             /* swap words */
391     move.w  %d7,(%a1)+      /* store high word */
392     cmp.l   %a0,%d0         /* any more longword? */
393     jls     .lines_do2_head_end    /* no: skip head loop */
395 .lines_do2_head_loop:
396     move.l  %d7,%d6         /* move old longword away */
397     move.l  (%a0)+,%d7      /* load new longword */
398     swap    %d7             /* swap words */
399     move.w  %d7,%d6         /* combine high word with old low word */
400     move.l  %d6,(%a1)+      /* store longword */
401     cmp.l   %a0,%d0         /* runs %a0 up to first line bound */
402     jhi     .lines_do2_head_loop
404 .lines_do2_head_end:
405     swap    %d7             /* undo swap */
406     move.w  %d7,(%a1)+      /* store word */
408 .lines_do2_selector:
409     move.l  %a1,%d1
410     lsr.l   #2,%d1
411     moveq.l #3,%d0          /* mask */
412     and.l   %d0,%d1
413     moveq.l #16,%d0         /* address increment for one main loop pass */
414     jmp.l   (2,%pc,%d1.l*4) /* switch ((dest_addr >> 2) & 3) */
415     bra.w   .lines_lo2_start
416     bra.w   .lines_lo6_start
417     bra.w   .lines_lo10_start
418  /* bra.w   .lines_lo14_start   implicit */
420     /* word aligned destination (line + 14): use line bursts in the loop */
421 .lines_lo14_start:
422     movem.l (%a0),%d4-%d7   /* load first line */
423     add.l   %d0,%a0
424     swap    %d4             /* swap words of 1st long */
425     move.w  %d4,(%a1)+      /* store word */
426     jra     .lines_lo14_entry      /* jump into main loop */
428 .lines_lo14_loop:
429     move.l  %d4,%d0         /* move old line away */
430     move.l  %d5,%d1
431     move.l  %d6,%d2
432     move.l  %d7,%d3
433     movem.l (%a0),%d4-%d7   /* load new line */
434     lea.l   (16,%a0),%a0
435     swap    %d4             /* swap words of 1st long */
436     move.w  %d4,%d3         /* combine 1st high word with old low word */
437     movem.l %d0-%d3,(%a1)   /* store line */
438     lea.l   (16,%a1),%a1
439 .lines_lo14_entry:
440     swap    %d5             /* swap words of 2nd long */
441     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
442     swap    %d6             /* swap words of 3rd long */
443     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
444     swap    %d7             /* swap words of 4th long */
445     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
446     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
447     jhi     .lines_lo14_loop
449     /* word aligned destination (line + 2/6/10/14): tail */
450 .lines_lo14_end:
451     move.l  %d4,(%a1)+      /* store third last longword */
452 .lines_lo10_end:
453     move.l  %d5,(%a1)+      /* store second last longword */
454 .lines_lo6_end:
455     move.l  %d6,(%a1)+      /* store last longword */
456 .lines_lo2_end:
457     lea.l   (12,%a2),%a2    /* readjust end address for doing longwords */
458     cmp.l   %a0,%a2         /* any trailing longwords? */
459     jls     .lines_do2_tail_end    /* no: skip tail loop */
460     
461 .lines_do2_tail_loop:
462     move.l  %d7,%d6         /* move old longword away */
463     move.l  (%a0)+,%d7      /* load new longword */
464     swap    %d7             /* swap words */
465     move.w  %d7,%d6         /* combine high word with old low word */
466     move.l  %d6,(%a1)+      /* store longword */
467     cmp.l   %a0,%a2         /* runs %a0 up to last long bound */
468     jhi     .lines_do2_tail_loop
470 .lines_do2_tail_end:
471     swap    %d7             /* undo swap */
472     move.w  %d7,(%a1)+      /* store last word */
473     jra     .lines_end  
475     /* word aligned destination (line + 2): use line bursts in the loop */
476 .lines_lo2_start:
477     movem.l (%a0),%d4-%d7   /* load first line */
478     add.l   %d0,%a0
479     swap    %d4             /* swap words of 1st long */
480     move.w  %d4,(%a1)+      /* store high word */
481     swap    %d5             /* swap words of 2nd long */
482     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
483     swap    %d6             /* swap words of 3rd long */
484     move.w  %d6,%d5         /* combine 3nd high word with 2nd low word */
485     swap    %d7             /* swap words of 4th long */
486     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
487     move.l  %d4,(%a1)+      /* store 1st longword */
488     move.l  %d5,(%a1)+      /* store 2nd longword */
489     move.l  %d6,(%a1)+      /* store 3rd longword */
490     cmp.l   %a0,%a2         /* any full lines? */
491     jls     .lines_lo2_end  /* no: skip main loop */
493 .lines_lo2_loop:
494     move.l  %d7,%d3         /* move last longword of old line away */
495     movem.l (%a0),%d4-%d7   /* load line */
496     add.l   %d0,%a0
497     swap    %d4             /* swap words of 1st long */
498     move.w  %d4,%d3         /* combine 1st high word with old low word */
499     swap    %d5             /* swap words of 2nd long */
500     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
501     swap    %d6             /* swap words of 3rd long */
502     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
503     swap    %d7             /* swap words of 4th long */
504     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
505     movem.l %d3-%d6,(%a1)   /* store line */
506     add.l   %d0,%a1
507     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
508     jhi     .lines_lo2_loop
510     jra     .lines_lo2_end  /* handle trailing longwords */
512     /* word aligned destination (line + 6): use line bursts in the loop */
513 .lines_lo6_start:
514     movem.l (%a0),%d4-%d7   /* load first line */
515     add.l   %d0,%a0
516     swap    %d4             /* swap words of 1st long */
517     move.w  %d4,(%a1)+      /* store high word */
518     swap    %d5             /* swap words of 2nd long */
519     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
520     swap    %d6             /* swap words of 3rd long */
521     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
522     move.l  %d4,(%a1)+      /* store 1st longword */
523     move.l  %d5,(%a1)+      /* store 2nd longword */
524     jra     .lines_lo6_entry       /* jump into main loop */
526 .lines_lo6_loop:
527     move.l  %d6,%d2         /* move last 2 longwords of old line away */
528     move.l  %d7,%d3
529     movem.l (%a0),%d4-%d7   /* load line */
530     add.l   %d0,%a0
531     swap    %d4             /* swap words of 1st long */
532     move.w  %d4,%d3         /* combine 1st high word with old low word */
533     swap    %d5             /* swap words of 2nd long */
534     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
535     swap    %d6             /* swap words of 3rd long */
536     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
537     movem.l %d2-%d5,(%a1)   /* store line */
538     add.l   %d0,%a1
539 .lines_lo6_entry:
540     swap    %d7             /* swap words of 4th long */
541     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
542     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
543     jhi     .lines_lo6_loop
545     jra     .lines_lo6_end  /* handle trailing longwords */
547     /* word aligned destination (line + 10): use line bursts in the loop */
548 .lines_lo10_start:
549     movem.l (%a0),%d4-%d7   /* load first line */
550     add.l   %d0,%a0
551     swap    %d4             /* swap words of 1st long */
552     move.w  %d4,(%a1)+      /* store high word */
553     swap    %d5             /* swap words of 2nd long */
554     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
555     move.l  %d4,(%a1)+      /* store 1st longword */
556     jra     .lines_lo10_entry      /* jump into main loop */
558 .lines_lo10_loop:
559     move.l  %d5,%d1         /* move last 3 longwords of old line away */
560     move.l  %d6,%d2
561     move.l  %d7,%d3
562     movem.l (%a0),%d4-%d7   /* load line */
563     add.l   %d0,%a0
564     swap    %d4             /* swap words of 1st long */
565     move.w  %d4,%d3         /* combine 1st high word with old low word */
566     swap    %d5             /* swap words of 2nd long */
567     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
568     movem.l %d1-%d4,(%a1)   /* store line */
569     add.l   %d0,%a1
570 .lines_lo10_entry:
571     swap    %d6             /* swap words of 3rd long */
572     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
573     swap    %d7             /* swap words of 4th long */
574     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
575     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
576     jhi     .lines_lo10_loop
578     jra     .lines_lo10_end /* handle trailing longwords */
580 #else /* !FULLSPEED */
582     /* word aligned destination (long + 2): use line burst reads in the loop */
583 .lines_do2_start:
584     cmp.l   %a0,%d0         /* any leading longwords? */
585     jhi     .lines_do2_head_start  /* yes: leading longword copy */
587     movem.l (%a0),%d4-%d7   /* load first line */
588     lea.l   (16,%a0),%a0
589     swap    %d4             /* swap words of 1st long */
590     move.w  %d4,(%a1)+      /* store high word */
591     jra     .lines_do2_entry       /* jump into main loop */
593 .lines_do2_head_start:
594     move.l  (%a0)+,%d7      /* load first longword */
595     swap    %d7             /* swap words */
596     move.w  %d7,(%a1)+      /* store high word */
597     cmp.l   %a0,%d0         /* any full longword? */
598     jls     .lines_do2_loop /* no: skip head loop */
600 .lines_do2_head_loop:
601     move.l  %d7,%d6         /* move old longword away */
602     move.l  (%a0)+,%d7      /* load new longword */
603     swap    %d7             /* swap words */
604     move.w  %d7,%d6         /* combine high word with old low word */
605     move.l  %d6,(%a1)+      /* store longword */
606     cmp.l   %a0,%d0         /* runs %a0 up to first line bound */
607     jhi     .lines_do2_head_loop
609 .lines_do2_loop:
610     move.l  %d7,%d3         /* move last longword of old line away */
611     movem.l (%a0),%d4-%d7   /* load line */
612     lea.l   (16,%a0),%a0
613     swap    %d4             /* swap words of 1st long */
614     move.w  %d4,%d3         /* combine 1st high word with old low word */
615     move.l  %d3,(%a1)+      /* store 1st longword */
616 .lines_do2_entry:
617     swap    %d5             /* swap words of 2nd long */
618     move.w  %d5,%d4         /* combine 2nd high word with 1st low word */
619     move.l  %d4,(%a1)+      /* store 2nd longword */
620     swap    %d6             /* swap words of 3rd long */
621     move.w  %d6,%d5         /* combine 3rd high word with 2nd low word */
622     move.l  %d5,(%a1)+      /* store 3rd longword */
623     swap    %d7             /* swap words of 4th long */
624     move.w  %d7,%d6         /* combine 4th high word with 3rd low word */
625     move.l  %d6,(%a1)+      /* store 4th longword */
626     cmp.l   %a0,%a2         /* runs %a0 up to last line bound */
627     jhi     .lines_do2_loop
629 .lines_do2_end:
630     lea.l   (12,%a2),%a2    /* readjust end address for doing longwords */
631     cmp.l   %a0,%a2         /* any trailing longwords? */
632     jls     .lines_do2_tail_end    /* no: skip tail loop */
633     
634 .lines_do2_tail_loop:
635     move.l  %d7,%d6         /* move old longword away */
636     move.l  (%a0)+,%d7      /* load new longword */
637     swap    %d7             /* swap words */
638     move.w  %d7,%d6         /* combine high word with old low word */
639     move.l  %d6,(%a1)+      /* store longword */
640     cmp.l   %a0,%a2         /* runs %a0 up to last long bound */
641     jhi     .lines_do2_tail_loop
643 .lines_do2_tail_end:
644     swap    %d7             /* undo swap */
645     move.w  %d7,(%a1)+      /* store last word */
646  /* jra     .lines_end    implicit */
648 #endif /* !FULLSPEED */
650 .lines_end:
651     addq.l  #3,%a2          /* readjust end address */
652     move.l  %a2,%d1         /* end address in %d1 again */
653     movem.l (%sp),%d2-%d7/%a2      /* restore registers */
654     lea.l   (28,%sp),%sp
655     jra     .bytes2_start   /* jump to trailing byte loop */
657 .long_start:
658     subq.l  #3,%d1          /* adjust end address for doing 4 bytes/ pass */
660     /* longword copy loop - no lines */
661 .long_loop:
662     move.l  (%a0)+,(%a1)+   /* copy longword (write can be unaligned) */
663     cmp.l   %a0,%d1         /* runs %a0 up to last long bound */
664     jhi     .long_loop
666     addq.l  #3,%d1          /* readjust end address */
667     cmp.l   %a0,%d1         /* any bytes left? */
668     jls     .bytes2_end     /* no: skip trailing byte loop */
670     /* trailing byte loop */
671 .bytes2_loop:
672     move.b  (%a0)+,(%a1)+   /* copy byte */
673 .bytes2_start:
674     cmp.l   %a0,%d1         /* runs %a0 up to end address */
675     jhi     .bytes2_loop
677 .bytes2_end:
678     move.l  (4,%sp),%d0     /* return destination */
679     rts
681 .end:
682     .size   memcpy,.end-memcpy