summaryrefslogtreecommitdiffstats
path: root/arch/arm/lib/io-readsw-armv4.S
blob: c92b66ecbe863f3df21e69c482add5f8b23efd05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 *  linux/arch/arm/lib/io-readsw-armv4.S
 *
 *  Copyright (C) 1995-2000 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>

		.macro	pack, rd, hw1, hw2
#ifndef __ARMEB__
		orr	\rd, \hw1, \hw2, lsl #16
#else
		orr	\rd, \hw2, \hw1, lsl #16
#endif
		.endm

.insw_align:	movs	ip, r1, lsl #31
		bne	.insw_noalign
		ldrh	ip, [r0]
		sub	r2, r2, #1
		strh	ip, [r1], #2

ENTRY(__raw_readsw)
		teq	r2, #0
		moveq	pc, lr
		tst	r1, #3
		bne	.insw_align

		stmfd	sp!, {r4, r5, lr}

		subs	r2, r2, #8
		bmi	.no_insw_8

.insw_8_lp:	ldrh	r3, [r0]
		ldrh	r4, [r0]
		pack	r3, r3, r4

		ldrh	r4, [r0]
		ldrh	r5, [r0]
		pack	r4, r4, r5

		ldrh	r5, [r0]
		ldrh	ip, [r0]
		pack	r5, r5, ip

		ldrh	ip, [r0]
		ldrh	lr, [r0]
		pack	ip, ip, lr

		subs	r2, r2, #8
		stmia	r1!, {r3 - r5, ip}
		bpl	.insw_8_lp

.no_insw_8:	tst	r2, #4
		beq	.no_insw_4

		ldrh	r3, [r0]
		ldrh	r4, [r0]
		pack	r3, r3, r4

		ldrh	r4, [r0]
		ldrh	ip, [r0]
		pack	r4, r4, ip

		stmia	r1!, {r3, r4}

.no_insw_4:	movs	r2, r2, lsl #31
		bcc	.no_insw_2

		ldrh	r3, [r0]
		ldrh	ip, [r0]
		pack	r3, r3, ip
		str	r3, [r1], #4

.no_insw_2:	ldrneh	r3, [r0]
		strneh	r3, [r1]

		ldmfd	sp!, {r4, r5, pc}

#ifdef __ARMEB__
#define _BE_ONLY_(code...)	code
#define _LE_ONLY_(code...)
#define push_hbyte0		lsr #8
#define pull_hbyte1		lsl #24
#else
#define _BE_ONLY_(code...)
#define _LE_ONLY_(code...) code
#define push_hbyte0		lsl #24
#define pull_hbyte1		lsr #8
#endif

.insw_noalign:	stmfd	sp!, {r4, lr}
		ldrccb	ip, [r1, #-1]!
		bcc	1f

		ldrh	ip, [r0]
		sub	r2, r2, #1
   _BE_ONLY_(	mov	ip, ip, ror #8		)
		strb	ip, [r1], #1
   _LE_ONLY_(	mov	ip, ip, lsr #8		)
   _BE_ONLY_(	mov	ip, ip, lsr #24		)

1:		subs	r2, r2, #2
		bmi	3f
   _BE_ONLY_(	mov	ip, ip, lsl #24		)

2:		ldrh	r3, [r0]
		ldrh	r4, [r0]
		subs	r2, r2, #2
		orr	ip, ip, r3, lsl #8
		orr	ip, ip, r4, push_hbyte0
		str	ip, [r1], #4
		mov	ip, r4, pull_hbyte1
		bpl	2b

   _BE_ONLY_(	mov	ip, ip, lsr #24		)

3:		tst	r2, #1
		strb	ip, [r1], #1
		ldrneh	ip, [r0]
   _BE_ONLY_(	movne	ip, ip, ror #8		)
		strneb	ip, [r1], #1
   _LE_ONLY_(	movne	ip, ip, lsr #8		)
   _BE_ONLY_(	movne	ip, ip, lsr #24		)
		strneb	ip, [r1]
		ldmfd	sp!, {r4, pc}