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