xref: /aosp_15_r20/external/tremolo/Tremolo/bitwiseARM.s (revision bda690e46497e1f65c5077173b9c548e6e0cd5a1)
1*bda690e4SXin Li@ Tremolo library
2*bda690e4SXin Li@-----------------------------------------------------------------------
3*bda690e4SXin Li@ Copyright (C) 2002-2009, Xiph.org Foundation
4*bda690e4SXin Li@ Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
5*bda690e4SXin Li@ All rights reserved.
6*bda690e4SXin Li
7*bda690e4SXin Li@ Redistribution and use in source and binary forms, with or without
8*bda690e4SXin Li@ modification, are permitted provided that the following conditions
9*bda690e4SXin Li@ are met:
10*bda690e4SXin Li
11*bda690e4SXin Li@     * Redistributions of source code must retain the above copyright
12*bda690e4SXin Li@ notice, this list of conditions and the following disclaimer.
13*bda690e4SXin Li@     * Redistributions in binary form must reproduce the above
14*bda690e4SXin Li@ copyright notice, this list of conditions and the following disclaimer
15*bda690e4SXin Li@ in the documentation and/or other materials provided with the
16*bda690e4SXin Li@ distribution.
17*bda690e4SXin Li@     * Neither the names of the Xiph.org Foundation nor Pinknoise
18*bda690e4SXin Li@ Productions Ltd nor the names of its contributors may be used to
19*bda690e4SXin Li@ endorse or promote products derived from this software without
20*bda690e4SXin Li@ specific prior written permission.
21*bda690e4SXin Li@
22*bda690e4SXin Li@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23*bda690e4SXin Li@ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24*bda690e4SXin Li@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25*bda690e4SXin Li@ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26*bda690e4SXin Li@ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27*bda690e4SXin Li@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28*bda690e4SXin Li@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29*bda690e4SXin Li@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30*bda690e4SXin Li@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*bda690e4SXin Li@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32*bda690e4SXin Li@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*bda690e4SXin Li@ ----------------------------------------------------------------------
34*bda690e4SXin Li
35*bda690e4SXin Li    .text
36*bda690e4SXin Li
37*bda690e4SXin Li	.global	oggpack_look
38*bda690e4SXin Li	.global	oggpack_adv
39*bda690e4SXin Li	.global	oggpack_readinit
40*bda690e4SXin Li	.global	oggpack_read
41*bda690e4SXin Li
42*bda690e4SXin Li	.type	oggpack_look, %function
43*bda690e4SXin Li	.type	oggpack_adv, %function
44*bda690e4SXin Li	.type	oggpack_readinit, %function
45*bda690e4SXin Li	.type	oggpack_read, %function
46*bda690e4SXin Li
47*bda690e4SXin Lioggpack_look:
48*bda690e4SXin Li	@ r0 = oggpack_buffer *b
49*bda690e4SXin Li	@ r1 = int             bits
50*bda690e4SXin Li	STMFD	r13!,{r10,r11,r14}
51*bda690e4SXin Li	LDMIA	r0,{r2,r3,r12}
52*bda690e4SXin Li					@ r2 = bitsLeftInSegment
53*bda690e4SXin Li					@ r3 = ptr
54*bda690e4SXin Li					@ r12= bitsLeftInWord
55*bda690e4SXin Li	SUBS	r2,r2,r1		@ bitsLeftinSegment -= bits
56*bda690e4SXin Li	BLT	look_slow		@ Not enough bits in this segment for
57*bda690e4SXin Li					@ this request. Do it slowly.
58*bda690e4SXin Li	LDR	r10,[r3]		@ r10= ptr[0]
59*bda690e4SXin Li	RSB	r14,r12,#32		@ r14= 32-bitsLeftInWord
60*bda690e4SXin Li	SUBS	r12,r12,r1		@ r12= bitsLeftInWord -= bits
61*bda690e4SXin Li	LDRLT	r11,[r3,#4]!		@ r11= ptr[1]
62*bda690e4SXin Li	MOV	r10,r10,LSR r14		@ r10= ptr[0]>>(32-bitsLeftInWord)
63*bda690e4SXin Li	ADDLE	r12,r12,#32		@ r12= bitsLeftInWord += 32
64*bda690e4SXin Li	RSB	r14,r14,#32		@ r14= 32-bitsLeftInWord
65*bda690e4SXin Li	ORRLT	r10,r10,r11,LSL r14	@ r10= Next 32 bits.
66*bda690e4SXin Li	MOV	r14,#1
67*bda690e4SXin Li	RSB	r14,r14,r14,LSL r1
68*bda690e4SXin Li	AND	r0,r10,r14
69*bda690e4SXin Li	LDMFD	r13!,{r10,r11,PC}
70*bda690e4SXin Li
71*bda690e4SXin Lilook_slow:
72*bda690e4SXin Li	STMFD	r13!,{r5,r6}
73*bda690e4SXin Li	ADDS	r10,r2,r1		@ r10= bitsLeftInSegment + bits (i.e.
74*bda690e4SXin Li					@ the initial value of bitsLeftInSeg)
75*bda690e4SXin Li	@ r10 = bitsLeftInSegment (initial)
76*bda690e4SXin Li	@ r12 = bitsLeftInWord
77*bda690e4SXin Li	RSB	r14,r12,#32		@ r14= 32-bitsLeftInWord
78*bda690e4SXin Li	MOV	r5,r10			@ r5 = bitsLeftInSegment (initial)
79*bda690e4SXin Li	BLT	look_overrun
80*bda690e4SXin Li	BEQ	look_next_segment	@ r10= r12 = 0, if we branch
81*bda690e4SXin Li	CMP	r12,r10			@ If bitsLeftInWord < bitsLeftInSeg
82*bda690e4SXin Li					@ there must be more in the next word
83*bda690e4SXin Li	LDR	r10,[r3],#4		@ r10= ptr[0]
84*bda690e4SXin Li	LDRLT	r6,[r3]			@ r6 = ptr[1]
85*bda690e4SXin Li	MOV	r11,#1
86*bda690e4SXin Li	MOV	r10,r10,LSR r14		@ r10= first bitsLeftInWord bits
87*bda690e4SXin Li	ORRLT	r10,r10,r6,LSL r12	@ r10= first bitsLeftInSeg bits+crap
88*bda690e4SXin Li	RSB	r11,r11,r11,LSL r5	@ r11= mask
89*bda690e4SXin Li	AND	r10,r10,r11		@ r10= first r5 bits
90*bda690e4SXin Li	@ Load the next segments data
91*bda690e4SXin Lilook_next_segment:
92*bda690e4SXin Li	@ At this point, r10 contains the first r5 bits of the result
93*bda690e4SXin Li	LDR	r11,[r0,#12]		@ r11= head = b->head
94*bda690e4SXin Li	@ Stall
95*bda690e4SXin Li	@ Stall
96*bda690e4SXin Lilook_next_segment_2:
97*bda690e4SXin Li	LDR	r11,[r11,#12]		@ r11= head = head->next
98*bda690e4SXin Li	@ Stall
99*bda690e4SXin Li	@ Stall
100*bda690e4SXin Li	CMP	r11,#0
101*bda690e4SXin Li	BEQ	look_out_of_data
102*bda690e4SXin Li	LDMIA	r11,{r6,r12,r14}	@ r6 = buffer
103*bda690e4SXin Li					@ r12= begin
104*bda690e4SXin Li					@ r14= length
105*bda690e4SXin Li	LDR	r6,[r6]			@ r6 = buffer->data
106*bda690e4SXin Li	CMP	r14,#0
107*bda690e4SXin Li	BEQ	look_next_segment_2
108*bda690e4SXin Li	ADD	r6,r6,r12		@ r6 = buffer->data+begin
109*bda690e4SXin Lilook_slow_loop:
110*bda690e4SXin Li	LDRB	r12,[r6],#1		@ r12= *buffer
111*bda690e4SXin Li	SUBS	r14,r14,#1		@ r14= length
112*bda690e4SXin Li	@ Stall
113*bda690e4SXin Li	ORR	r10,r10,r12,LSL r5	@ r10= first r5+8 bits
114*bda690e4SXin Li	ADD	r5,r5,#8
115*bda690e4SXin Li	BLE	look_really_slow
116*bda690e4SXin Li	CMP	r5,r1
117*bda690e4SXin Li	BLT	look_slow_loop
118*bda690e4SXin Li	MOV	r14,#1
119*bda690e4SXin Li	RSB	r14,r14,r14,LSL r1
120*bda690e4SXin Li	AND	r0,r10,r14
121*bda690e4SXin Li	LDMFD	r13!,{r5,r6,r10,r11,PC}
122*bda690e4SXin Li
123*bda690e4SXin Li
124*bda690e4SXin Lilook_really_slow:
125*bda690e4SXin Li	CMP	r5,r1
126*bda690e4SXin Li	BLT	look_next_segment_2
127*bda690e4SXin Li	MOV	r14,#1
128*bda690e4SXin Li	RSB	r14,r14,r14,LSL r1
129*bda690e4SXin Li	AND	r0,r10,r14
130*bda690e4SXin Li	LDMFD	r13!,{r5,r6,r10,r11,PC}
131*bda690e4SXin Li
132*bda690e4SXin Lilook_out_of_data:
133*bda690e4SXin Li	@MVN	r0,#0			; return -1
134*bda690e4SXin Li	MOV	r0,#0
135*bda690e4SXin Li	LDMFD	r13!,{r5,r6,r10,r11,PC}
136*bda690e4SXin Li
137*bda690e4SXin Lilook_overrun:
138*bda690e4SXin Li	@ We had overrun when we started, so we need to skip -r10 bits.
139*bda690e4SXin Li	LDR	r11,[r0,#12]		@ r11 = head = b->head
140*bda690e4SXin Li	@ stall
141*bda690e4SXin Li	@ stall
142*bda690e4SXin Lilook_overrun_next_segment:
143*bda690e4SXin Li	LDR	r11,[r11,#12]		@ r11 = head->next
144*bda690e4SXin Li	@ stall
145*bda690e4SXin Li	@ stall
146*bda690e4SXin Li	CMP	r11,#0
147*bda690e4SXin Li	BEQ	look_out_of_data
148*bda690e4SXin Li	LDMIA	r11,{r6,r7,r14}		@ r6 = buffer
149*bda690e4SXin Li					@ r7 = begin
150*bda690e4SXin Li					@ r14= length
151*bda690e4SXin Li	LDR	r6,[r6]			@ r6 = buffer->data
152*bda690e4SXin Li	@ stall
153*bda690e4SXin Li	@ stall
154*bda690e4SXin Li	ADD	r6,r6,r7		@ r6 = buffer->data+begin
155*bda690e4SXin Li	MOV	r14,r14,LSL #3		@ r14= length in bits
156*bda690e4SXin Li	ADDS	r14,r14,r10		@ r14= length in bits-bits to skip
157*bda690e4SXin Li	MOVLE	r10,r14
158*bda690e4SXin Li	BLE	look_overrun_next_segment
159*bda690e4SXin Li	RSB	r10,r10,#0		@ r10= bits to skip
160*bda690e4SXin Li	ADD	r6,r10,r10,LSR #3	@ r6 = pointer to data
161*bda690e4SXin Li	MOV	r10,#0
162*bda690e4SXin Li	B	look_slow_loop
163*bda690e4SXin Li
164*bda690e4SXin Lioggpack_adv:
165*bda690e4SXin Li	@ r0 = oggpack_buffer *b
166*bda690e4SXin Li	@ r1 = bits
167*bda690e4SXin Li	LDMIA	r0,{r2,r3,r12}
168*bda690e4SXin Li					@ r2 = bitsLeftInSegment
169*bda690e4SXin Li					@ r3 = ptr
170*bda690e4SXin Li					@ r12= bitsLeftInWord
171*bda690e4SXin Li	SUBS	r2,r2,r1		@ Does this run us out of bits in the
172*bda690e4SXin Li	BLE	adv_slow		@ segment? If so, do it slowly
173*bda690e4SXin Li	SUBS	r12,r12,r1
174*bda690e4SXin Li	ADDLE	r12,r12,#32
175*bda690e4SXin Li	ADDLE	r3,r3,#4
176*bda690e4SXin Li	STMIA	r0,{r2,r3,r12}
177*bda690e4SXin Li	BX      LR
178*bda690e4SXin Liadv_slow:
179*bda690e4SXin Li	STMFD	r13!,{r10,r14}
180*bda690e4SXin Li
181*bda690e4SXin Li	LDR	r14,[r0,#12]		@ r14= head
182*bda690e4SXin Li	@ stall
183*bda690e4SXin Liadv_slow_loop:
184*bda690e4SXin Li	LDR	r1,[r0,#20]		@ r1 = count
185*bda690e4SXin Li	LDR	r10,[r14,#8]		@ r10= head->length
186*bda690e4SXin Li	LDR	r14,[r14,#12]		@ r14= head->next
187*bda690e4SXin Li	@ stall
188*bda690e4SXin Li	ADD	r1,r1,r10		@ r1 = count += head->length
189*bda690e4SXin Li	CMP	r14,#0
190*bda690e4SXin Li	BEQ	adv_end
191*bda690e4SXin Li	STR	r1,[r0,#20]		@ b->count = count
192*bda690e4SXin Li	STR	r14,[r0,#12]		@ b->head = head
193*bda690e4SXin Li	LDMIA	r14,{r3,r10,r12}	@ r3 = buffer
194*bda690e4SXin Li					@ r10= begin
195*bda690e4SXin Li					@ r12= length
196*bda690e4SXin Li	LDR	r3,[r3]			@ r3 = buffer->data
197*bda690e4SXin Li	ADD	r3,r3,r10		@ r3 = Pointer to start (byte)
198*bda690e4SXin Li	AND	r10,r3,#3		@ r10= bytes to backtrk to word align
199*bda690e4SXin Li	MOV	r10,r10,LSL #3		@ r10= bits to backtrk to word align
200*bda690e4SXin Li	RSB	r10,r10,#32		@ r10= bits left in word
201*bda690e4SXin Li	ADDS	r10,r10,r2		@ r10= bits left in word after skip
202*bda690e4SXin Li	ADDLE	r10,r10,#32
203*bda690e4SXin Li	ADDLE	r3,r3,#4
204*bda690e4SXin Li	BIC	r3,r3,#3		@ r3 = Pointer to start (word)
205*bda690e4SXin Li	ADDS	r2,r2,r12,LSL #3	@ r2 = length in bits after advance
206*bda690e4SXin Li	BLE	adv_slow_loop
207*bda690e4SXin Li	STMIA	r0,{r2,r3,r10}
208*bda690e4SXin Li
209*bda690e4SXin Li	LDMFD	r13!,{r10,PC}
210*bda690e4SXin Liadv_end:
211*bda690e4SXin Li	MOV	r2, #0
212*bda690e4SXin Li	MOV	r12,#0
213*bda690e4SXin Li	STMIA	r0,{r2,r3,r12}
214*bda690e4SXin Li
215*bda690e4SXin Li	LDMFD	r13!,{r10,PC}
216*bda690e4SXin Li
217*bda690e4SXin Lioggpack_readinit:
218*bda690e4SXin Li	@ r0 = oggpack_buffer *b
219*bda690e4SXin Li	@ r1 = oggreference   *r
220*bda690e4SXin Li	STR	r1,[r0,#12]		@ b->head = r1
221*bda690e4SXin Li	STR	r1,[r0,#16]		@ b->tail = r1
222*bda690e4SXin Li	LDMIA	r1,{r2,r3,r12}		@ r2 = b->head->buffer
223*bda690e4SXin Li					@ r3 = b->head->begin
224*bda690e4SXin Li					@ r12= b->head->length
225*bda690e4SXin Li	LDR	r2,[r2]			@ r2 = b->head->buffer->data
226*bda690e4SXin Li	MOV	r1,r12,LSL #3		@ r1 = BitsInSegment
227*bda690e4SXin Li	MOV	r12,#0
228*bda690e4SXin Li	ADD	r3,r2,r3		@ r3 = r2+b->head->begin
229*bda690e4SXin Li	BIC	r2,r3,#3		@ r2 = b->headptr (word)
230*bda690e4SXin Li	AND	r3,r3,#3
231*bda690e4SXin Li	MOV	r3,r3,LSL #3
232*bda690e4SXin Li	RSB	r3,r3,#32		@ r3 = BitsInWord
233*bda690e4SXin Li	STMIA	r0,{r1,r2,r3}
234*bda690e4SXin Li	STR	r12,[r0,#20]
235*bda690e4SXin Li	BX      LR
236*bda690e4SXin Li
237*bda690e4SXin Lioggpack_read:
238*bda690e4SXin Li	@ r0 = oggpack_buffer *b
239*bda690e4SXin Li	@ r1 = int             bits
240*bda690e4SXin Li	STMFD	r13!,{r10,r11,r14}
241*bda690e4SXin Li	LDMIA	r0,{r2,r3,r12}
242*bda690e4SXin Li					@ r2 = bitsLeftInSegment
243*bda690e4SXin Li					@ r3 = ptr
244*bda690e4SXin Li					@ r12= bitsLeftInWord
245*bda690e4SXin Li	SUBS	r2,r2,r1		@ bitsLeftinSegment -= bits
246*bda690e4SXin Li	BLT	read_slow		@ Not enough bits in this segment for
247*bda690e4SXin Li					@ this request. Do it slowly.
248*bda690e4SXin Li	LDR	r10,[r3]		@ r10= ptr[0]
249*bda690e4SXin Li	RSB	r14,r12,#32		@ r14= 32-bitsLeftInWord
250*bda690e4SXin Li	SUBS	r12,r12,r1		@ r12= bitsLeftInWord -= bits
251*bda690e4SXin Li	ADDLE	r3,r3,#4
252*bda690e4SXin Li	LDRLT	r11,[r3]		@ r11= ptr[1]
253*bda690e4SXin Li	MOV	r10,r10,LSR r14		@ r10= ptr[0]>>(32-bitsLeftInWord)
254*bda690e4SXin Li	ADDLE	r12,r12,#32		@ r12= bitsLeftInWord += 32
255*bda690e4SXin Li	RSB	r14,r14,#32		@ r14= 32-bitsLeftInWord
256*bda690e4SXin Li	ORRLT	r10,r10,r11,LSL r14	@ r10= Next 32 bits.
257*bda690e4SXin Li	STMIA	r0,{r2,r3,r12}
258*bda690e4SXin Li	MOV	r14,#1
259*bda690e4SXin Li	RSB	r14,r14,r14,LSL r1
260*bda690e4SXin Li	AND	r0,r10,r14
261*bda690e4SXin Li	LDMFD	r13!,{r10,r11,PC}
262*bda690e4SXin Li
263*bda690e4SXin Liread_slow:
264*bda690e4SXin Li	STMFD	r13!,{r5,r6}
265*bda690e4SXin Li	ADDS	r10,r2,r1		@ r10= bitsLeftInSegment + bits (i.e.
266*bda690e4SXin Li					@ the initial value of bitsLeftInSeg)
267*bda690e4SXin Li	@ r10 = bitsLeftInSegment (initial)
268*bda690e4SXin Li	@ r12 = bitsLeftInWord
269*bda690e4SXin Li	RSB	r14,r12,#32		@ r14= 32-bitsLeftInWord
270*bda690e4SXin Li	MOV	r5,r10			@ r5 = bitsLeftInSegment (initial)
271*bda690e4SXin Li	BLT	read_overrun
272*bda690e4SXin Li	BEQ	read_next_segment	@ r10= r12 = 0, if we branch
273*bda690e4SXin Li	CMP	r12,r10			@ If bitsLeftInWord < bitsLeftInSeg
274*bda690e4SXin Li					@ there must be more in the next word
275*bda690e4SXin Li	LDR	r10,[r3],#4		@ r10= ptr[0]
276*bda690e4SXin Li	LDRLT	r6,[r3]			@ r6 = ptr[1]
277*bda690e4SXin Li	MOV	r11,#1
278*bda690e4SXin Li	MOV	r10,r10,LSR r14		@ r10= first bitsLeftInWord bits
279*bda690e4SXin Li	ORRLT	r10,r10,r6,LSL r12	@ r10= first bitsLeftInSeg bits+crap
280*bda690e4SXin Li	RSB	r11,r11,r11,LSL r5	@ r11= mask
281*bda690e4SXin Li	AND	r10,r10,r11		@ r10= first r5 bits
282*bda690e4SXin Li	@ Load the next segments data
283*bda690e4SXin Liread_next_segment:
284*bda690e4SXin Li	@ At this point, r10 contains the first r5 bits of the result
285*bda690e4SXin Li	LDR	r11,[r0,#12]		@ r11= head = b->head
286*bda690e4SXin Li	@ Stall
287*bda690e4SXin Liread_next_segment_2:
288*bda690e4SXin Li	@ r11 = head
289*bda690e4SXin Li	LDR	r6,[r0,#20]		@ r6 = count
290*bda690e4SXin Li	LDR	r12,[r11,#8]		@ r12= length
291*bda690e4SXin Li	LDR	r11,[r11,#12]		@ r11= head = head->next
292*bda690e4SXin Li	@ Stall
293*bda690e4SXin Li	ADD	r6,r6,r12		@ count += length
294*bda690e4SXin Li	CMP	r11,#0
295*bda690e4SXin Li	BEQ	read_out_of_data
296*bda690e4SXin Li	STR	r11,[r0,#12]
297*bda690e4SXin Li	STR	r6,[r0,#20]		@ b->count = count
298*bda690e4SXin Li	LDMIA	r11,{r6,r12,r14}	@ r6 = buffer
299*bda690e4SXin Li					@ r12= begin
300*bda690e4SXin Li					@ r14= length
301*bda690e4SXin Li	LDR	r6,[r6]			@ r6 = buffer->data
302*bda690e4SXin Li	CMP	r14,#0
303*bda690e4SXin Li	BEQ	read_next_segment_2
304*bda690e4SXin Li	ADD	r6,r6,r12		@ r6 = buffer->data+begin
305*bda690e4SXin Liread_slow_loop:
306*bda690e4SXin Li	LDRB	r12,[r6],#1		@ r12= *buffer
307*bda690e4SXin Li	SUBS	r14,r14,#1		@ r14= length
308*bda690e4SXin Li	@ Stall
309*bda690e4SXin Li	ORR	r10,r10,r12,LSL r5	@ r10= first r5+8 bits
310*bda690e4SXin Li	ADD	r5,r5,#8
311*bda690e4SXin Li	BLE	read_really_slow
312*bda690e4SXin Li	CMP	r5,r1
313*bda690e4SXin Li	BLT	read_slow_loop
314*bda690e4SXin Liread_end:
315*bda690e4SXin Li	MOV	r12,#1
316*bda690e4SXin Li	RSB	r12,r12,r12,LSL r1
317*bda690e4SXin Li
318*bda690e4SXin Li	@ Store back the new position
319*bda690e4SXin Li	@ r2 = -number of bits to go from this segment
320*bda690e4SXin Li	@ r6 = ptr
321*bda690e4SXin Li	@ r14= bytesLeftInSegment
322*bda690e4SXin Li	@ r11= New head value
323*bda690e4SXin Li	LDMIA	r11,{r3,r6,r14}		@ r3 = buffer
324*bda690e4SXin Li					@ r6 = begin
325*bda690e4SXin Li					@ r14= length
326*bda690e4SXin Li	LDR	r3,[r3]			@ r3 = buffer->data
327*bda690e4SXin Li	ADD	r1,r2,r14,LSL #3	@ r1 = bitsLeftInSegment
328*bda690e4SXin Li	@ stall
329*bda690e4SXin Li	ADD	r6,r3,r6		@ r6 = pointer
330*bda690e4SXin Li	AND	r3,r6,#3		@ r3 = bytes used in first word
331*bda690e4SXin Li	RSB	r3,r2,r3,LSL #3		@ r3 = bits used in first word
332*bda690e4SXin Li	BIC	r2,r6,#3		@ r2 = word ptr
333*bda690e4SXin Li	RSBS	r3,r3,#32		@ r3 = bitsLeftInWord
334*bda690e4SXin Li	ADDLE	r3,r3,#32
335*bda690e4SXin Li	ADDLE	r2,r2,#4
336*bda690e4SXin Li	STMIA	r0,{r1,r2,r3}
337*bda690e4SXin Li
338*bda690e4SXin Li	AND	r0,r10,r12
339*bda690e4SXin Li	LDMFD	r13!,{r5,r6,r10,r11,PC}
340*bda690e4SXin Li
341*bda690e4SXin Li
342*bda690e4SXin Liread_really_slow:
343*bda690e4SXin Li	CMP	r5,r1
344*bda690e4SXin Li	BGE	read_end
345*bda690e4SXin Li	LDR	r14,[r11,#8]		@ r14= length of segment just done
346*bda690e4SXin Li	@ stall
347*bda690e4SXin Li	@ stall
348*bda690e4SXin Li	ADD	r2,r2,r14,LSL #3	@ r2 = -bits to use from next seg
349*bda690e4SXin Li	B	read_next_segment_2
350*bda690e4SXin Li
351*bda690e4SXin Liread_out_of_data:
352*bda690e4SXin Li	@ Store back the new position
353*bda690e4SXin Li	@ r2 = -number of bits to go from this segment
354*bda690e4SXin Li	@ r6 = ptr
355*bda690e4SXin Li	@ r14= bytesLeftInSegment
356*bda690e4SXin Li	@ RJW: This may be overkill - we leave the buffer empty, with -1
357*bda690e4SXin Li	@ bits left in it. We might get away with just storing the
358*bda690e4SXin Li	@ bitsLeftInSegment as -1.
359*bda690e4SXin Li	LDR	r11,[r0,#12]		@ r11=head
360*bda690e4SXin Li
361*bda690e4SXin Li	LDMIA	r11,{r3,r6,r14}		@ r3 = buffer
362*bda690e4SXin Li					@ r6 = begin
363*bda690e4SXin Li					@ r14= length
364*bda690e4SXin Li	LDR	r3,[r3]			@ r3 = buffer->data
365*bda690e4SXin Li	ADD	r6,r3,r6		@ r6 = pointer
366*bda690e4SXin Li	ADD	r6,r6,r14
367*bda690e4SXin Li	AND	r3,r6,#3		@ r3 = bytes used in first word
368*bda690e4SXin Li	MOV	r3,r3,LSL #3		@ r3 = bits used in first word
369*bda690e4SXin Li	BIC	r2,r6,#3		@ r2 = word ptr
370*bda690e4SXin Li	RSBS	r3,r3,#32		@ r3 = bitsLeftInWord
371*bda690e4SXin Li	MVN	r1,#0			@ r1 = -1 = bitsLeftInSegment
372*bda690e4SXin Li	STMIA	r0,{r1,r2,r3}
373*bda690e4SXin Li	@MVN	r0,#0			; return -1
374*bda690e4SXin Li	MOV	r0,#0
375*bda690e4SXin Li	LDMFD	r13!,{r5,r6,r10,r11,PC}
376*bda690e4SXin Li
377*bda690e4SXin Liread_overrun:
378*bda690e4SXin Li	@ We had overrun when we started, so we need to skip -r10 bits.
379*bda690e4SXin Li	LDR	r11,[r0,#12]		@ r11 = head = b->head
380*bda690e4SXin Li	@ stall
381*bda690e4SXin Li	@ stall
382*bda690e4SXin Liread_overrun_next_segment:
383*bda690e4SXin Li	LDR	r11,[r11,#12]		@ r11 = head->next
384*bda690e4SXin Li	@ stall
385*bda690e4SXin Li	@ stall
386*bda690e4SXin Li	CMP	r11,#0
387*bda690e4SXin Li	BEQ	read_out_of_data
388*bda690e4SXin Li	LDMIA	r11,{r6,r7,r14}		@ r6 = buffer
389*bda690e4SXin Li					@ r7 = begin
390*bda690e4SXin Li					@ r14= length
391*bda690e4SXin Li	LDR	r6,[r6]			@ r6 = buffer->data
392*bda690e4SXin Li	@ stall
393*bda690e4SXin Li	@ stall
394*bda690e4SXin Li	ADD	r6,r6,r7		@ r6 = buffer->data+begin
395*bda690e4SXin Li	MOV	r14,r14,LSL #3		@ r14= length in bits
396*bda690e4SXin Li	ADDS	r14,r14,r10		@ r14= length in bits-bits to skip
397*bda690e4SXin Li	MOVLE	r10,r14
398*bda690e4SXin Li	BLE	read_overrun_next_segment
399*bda690e4SXin Li	RSB	r10,r10,#0		@ r10= bits to skip
400*bda690e4SXin Li	ADD	r6,r10,r10,LSR #3	@ r6 = pointer to data
401*bda690e4SXin Li	MOV	r10,#0
402*bda690e4SXin Li	B	read_slow_loop
403*bda690e4SXin Li
404*bda690e4SXin Li	@ END
405