1/*        $NetBSD: w16copy.s,v 1.4 2023/09/26 12:46:30 tsutsui Exp $  */
2
3/*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Fredette.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * NOTICE: This is not a standalone file.  To use it, #include it in
34 * your port's locore.s, like so:
35 *
36 *        #include <m68k/m68k/w16copy.s>
37 */
38
39/*
40 * Function to zero a region of memory using only
41 * properly aligned 8- and 16-bit accesses.
42 */
43ENTRY(w16zero)
44          movl      8(%sp), %d0                   | get our count
45          beq       6f                            | return if count is zero
46          movl      4(%sp), %a0                   | get our address
47
48| align %a0 to a 16-bit boundary:
49          movl      %a0, %d1
50          btst      #0, %d1                       | is %a0 even?
51          beq       1f                            | if so, skip ahead
52          clrb      (%a0)+                        | zero one byte
53          subql     #1, %d0                       | decrement count
54
55| now zero 32 bits at a time:
561:        movl      %d0, %d1            | copy count into %d1
57          lsrl      #2, %d1                       | turn %d1 into long count
58          subqw     #1, %d1                       | set up for dbf
59          bcs       3f                            | skip ahead if long count % 64k == 0
60#ifdef    __mc68010__
61| on a 68010, 32-bit accesses become 16-bit accesses externally:
622:        clrl      (%a0)+
63          dbf       %d1, 2b                       | will use the 68010 loop mode
64#else     /* !__mc68010__ */
652:        clrw      (%a0)+
66          clrw      (%a0)+
67          dbf       %d1, 2b
68#endif    /* !__mc68010__ */
69| since DBcc only uses the low 16-bits of the count
70| register, we have to decrement the high 16-bits:
713:        subil     #0x10000, %d1
72          bcc       2b
73
74| zero the odd bytes:
754:        andil     #3, %d0                       | odd byte count in %d0
76          subqw     #1, %d0                       | set up for dbf
77          bcs       6f                            | skip ahead if no odd bytes
785:        clrb      (%a0)+
79          dbf       %d0, 5b                       | will use the 68010 loop mode
80
816:        rts
82
83/*
84 * Function to copy a region of memory to a nonoverlapping
85 * region of memory using only properly aligned 8- and
86 * 16-bit accesses.
87 */
88ENTRY(w16copy)
89          movl      12(%sp), %d0                  | get our count
90          beq       8f                            | return if count is zero
91          movl      4(%sp), %a0                   | get our source address
92          movl      8(%sp), %a1                   | get our destination address
93
94| align %a0 to a 16-bit boundary:
95          movl      %a0, %d1
96          btst      #0, %d1                       | is %a0 even?
97          beq       1f                            | if so, skip ahead
98          movb      (%a0)+, (%a1)+                | copy one byte
99          subql     #1, %d0                       | decrement count
100
101| branch on whether or not %a1 is aligned to a 16-bit boundary:
1021:        movl      %a1, %d1
103          btst      #0, %d1                       | is %a1 even?
104          bne       4f                            | if not, skip ahead
105
106| %a1 is also aligned to a 16-bit boundary, so we can copy
107| the easy way, 32 bits at a time:
108          movl      %d0, %d1            | copy count into %d1
109          lsrl      #2, %d1                       | turn %d1 into long count
110          subqw     #1, %d1                       | set up for dbf
111          bcs       3f                            | skip ahead if long count % 64k == 0
112#ifdef    __mc68010__
113| on a 68010, 32-bit accesses become 16-bit accesses externally:
1142:        movl      (%a0)+, (%a1)+
115          dbf       %d1, 2b                       | will use the 68010 loop mode
116#else     /* !__mc68010__ */
1172:        movw      (%a0)+, (%a1)+
118          movw      (%a0)+, (%a1)+
119          dbf       %d1, 2b
120#endif    /* !__mc68010__ */
121| since DBcc only uses the low 16-bits of the count
122| register, we have to decrement the high 16-bits:
1233:        subil     #0x10000, %d1
124          bcc       2b
125          bra       6f                            | jump ahead to copy the odd bytes
126
127| %a1 is misaligned, so we're forced to copy the hard way.
128| if there are fewer than four bytes, copy only odd bytes:
1294:        cmpil     #4, %d0                       | is count less than 4?
130          bcs       6f                            | if so, skip ahead
131| prime the FIFO:
132          movw      (%a0)+, %d1                   | FIFO: xx01
133          rorl      #8, %d1                       | FIFO: 1xx0
134          movb      %d1, (%a1)+                   | FIFO: 1xxx
135          subql     #4, %d0                       | subtract 4 from count
136| run the FIFO:
1375:        rorl      #8, %d1                       | FIFO: x1xx
138          movw      (%a0)+, %d1                   | FIFO: x123
139          rorl      #8, %d1                       | FIFO: 3x12
140          movw      %d1, (%a1)+                   | FIFO: 3xxx -> 1xxx
141          subql     #2, %d0                       | two or more bytes remaining?
142          bcc       5b                            | loop back, if so.
143| flush the FIFO:
144          roll      #8, %d1                       | FIFO: xxx1
145          movb      %d1, (%a1)+                   | FIFO: xxxx
146          addl      #2, %d0                       | fix up count
147
148| copy the odd bytes:
1496:        andil     #3, %d0                       | odd byte count in %d0
150          subqw     #1, %d0                       | set up for dbf
151          bcs       8f                            | skip ahead if no odd bytes
1527:        movb      (%a0)+, (%a1)+
153          dbf       %d0, 7b                       | use loop mode
154
1558:        rts
156