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 42 .type oggpack_look, %function 43 .type oggpack_adv, %function 44 .type oggpack_readinit, %function 45 .type oggpack_read, %function 46 47oggpack_look: 48 @ r0 = oggpack_buffer *b 49 @ r1 = int bits 50 STMFD r13!,{r10,r11,r14} 51 LDMIA r0,{r2,r3,r12} 52 @ r2 = bitsLeftInSegment 53 @ r3 = ptr 54 @ r12= bitsLeftInWord 55 SUBS r2,r2,r1 @ bitsLeftinSegment -= bits 56 BLT look_slow @ Not enough bits in this segment for 57 @ this request. Do it slowly. 58 LDR r10,[r3] @ r10= ptr[0] 59 RSB r14,r12,#32 @ r14= 32-bitsLeftInWord 60 SUBS r12,r12,r1 @ r12= bitsLeftInWord -= bits 61 LDRLT r11,[r3,#4]! @ r11= ptr[1] 62 MOV r10,r10,LSR r14 @ r10= ptr[0]>>(32-bitsLeftInWord) 63 ADDLE r12,r12,#32 @ r12= bitsLeftInWord += 32 64 RSB r14,r14,#32 @ r14= 32-bitsLeftInWord 65 ORRLT r10,r10,r11,LSL r14 @ r10= Next 32 bits. 66 MOV r14,#1 67 RSB r14,r14,r14,LSL r1 68 AND r0,r10,r14 69 LDMFD r13!,{r10,r11,PC} 70 71look_slow: 72 STMFD r13!,{r5,r6} 73 ADDS r10,r2,r1 @ r10= bitsLeftInSegment + bits (i.e. 74 @ the initial value of bitsLeftInSeg) 75 @ r10 = bitsLeftInSegment (initial) 76 @ r12 = bitsLeftInWord 77 RSB r14,r12,#32 @ r14= 32-bitsLeftInWord 78 MOV r5,r10 @ r5 = bitsLeftInSegment (initial) 79 BLT look_overrun 80 BEQ look_next_segment @ r10= r12 = 0, if we branch 81 CMP r12,r10 @ If bitsLeftInWord < bitsLeftInSeg 82 @ there must be more in the next word 83 LDR r10,[r3],#4 @ r10= ptr[0] 84 LDRLT r6,[r3] @ r6 = ptr[1] 85 MOV r11,#1 86 MOV r10,r10,LSR r14 @ r10= first bitsLeftInWord bits 87 ORRLT r10,r10,r6,LSL r12 @ r10= first bitsLeftInSeg bits+crap 88 RSB r11,r11,r11,LSL r5 @ r11= mask 89 AND r10,r10,r11 @ r10= first r5 bits 90 @ Load the next segments data 91look_next_segment: 92 @ At this point, r10 contains the first r5 bits of the result 93 LDR r11,[r0,#12] @ r11= head = b->head 94 @ Stall 95 @ Stall 96look_next_segment_2: 97 LDR r11,[r11,#12] @ r11= head = head->next 98 @ Stall 99 @ Stall 100 CMP r11,#0 101 BEQ look_out_of_data 102 LDMIA r11,{r6,r12,r14} @ r6 = buffer 103 @ r12= begin 104 @ r14= length 105 LDR r6,[r6] @ r6 = buffer->data 106 CMP r14,#0 107 BEQ look_next_segment_2 108 ADD r6,r6,r12 @ r6 = buffer->data+begin 109look_slow_loop: 110 LDRB r12,[r6],#1 @ r12= *buffer 111 SUBS r14,r14,#1 @ r14= length 112 @ Stall 113 ORR r10,r10,r12,LSL r5 @ r10= first r5+8 bits 114 ADD r5,r5,#8 115 BLE look_really_slow 116 CMP r5,r1 117 BLT look_slow_loop 118 MOV r14,#1 119 RSB r14,r14,r14,LSL r1 120 AND r0,r10,r14 121 LDMFD r13!,{r5,r6,r10,r11,PC} 122 123 124look_really_slow: 125 CMP r5,r1 126 BLT look_next_segment_2 127 MOV r14,#1 128 RSB r14,r14,r14,LSL r1 129 AND r0,r10,r14 130 LDMFD r13!,{r5,r6,r10,r11,PC} 131 132look_out_of_data: 133 @MVN r0,#0 ; return -1 134 MOV r0,#0 135 LDMFD r13!,{r5,r6,r10,r11,PC} 136 137look_overrun: 138 @ We had overrun when we started, so we need to skip -r10 bits. 139 LDR r11,[r0,#12] @ r11 = head = b->head 140 @ stall 141 @ stall 142look_overrun_next_segment: 143 LDR r11,[r11,#12] @ r11 = head->next 144 @ stall 145 @ stall 146 CMP r11,#0 147 BEQ look_out_of_data 148 LDMIA r11,{r6,r7,r14} @ r6 = buffer 149 @ r7 = begin 150 @ r14= length 151 LDR r6,[r6] @ r6 = buffer->data 152 @ stall 153 @ stall 154 ADD r6,r6,r7 @ r6 = buffer->data+begin 155 MOV r14,r14,LSL #3 @ r14= length in bits 156 ADDS r14,r14,r10 @ r14= length in bits-bits to skip 157 MOVLE r10,r14 158 BLE look_overrun_next_segment 159 RSB r10,r10,#0 @ r10= bits to skip 160 ADD r6,r10,r10,LSR #3 @ r6 = pointer to data 161 MOV r10,#0 162 B look_slow_loop 163 164oggpack_adv: 165 @ r0 = oggpack_buffer *b 166 @ r1 = bits 167 LDMIA r0,{r2,r3,r12} 168 @ r2 = bitsLeftInSegment 169 @ r3 = ptr 170 @ r12= bitsLeftInWord 171 SUBS r2,r2,r1 @ Does this run us out of bits in the 172 BLE adv_slow @ segment? If so, do it slowly 173 SUBS r12,r12,r1 174 ADDLE r12,r12,#32 175 ADDLE r3,r3,#4 176 STMIA r0,{r2,r3,r12} 177 BX LR 178adv_slow: 179 STMFD r13!,{r10,r14} 180 181 LDR r14,[r0,#12] @ r14= head 182 @ stall 183adv_slow_loop: 184 LDR r1,[r0,#20] @ r1 = count 185 LDR r10,[r14,#8] @ r10= head->length 186 LDR r14,[r14,#12] @ r14= head->next 187 @ stall 188 ADD r1,r1,r10 @ r1 = count += head->length 189 CMP r14,#0 190 BEQ adv_end 191 STR r1,[r0,#20] @ b->count = count 192 STR r14,[r0,#12] @ b->head = head 193 LDMIA r14,{r3,r10,r12} @ r3 = buffer 194 @ r10= begin 195 @ r12= length 196 LDR r3,[r3] @ r3 = buffer->data 197 ADD r3,r3,r10 @ r3 = Pointer to start (byte) 198 AND r10,r3,#3 @ r10= bytes to backtrk to word align 199 MOV r10,r10,LSL #3 @ r10= bits to backtrk to word align 200 RSB r10,r10,#32 @ r10= bits left in word 201 ADDS r10,r10,r2 @ r10= bits left in word after skip 202 ADDLE r10,r10,#32 203 ADDLE r3,r3,#4 204 BIC r3,r3,#3 @ r3 = Pointer to start (word) 205 ADDS r2,r2,r12,LSL #3 @ r2 = length in bits after advance 206 BLE adv_slow_loop 207 STMIA r0,{r2,r3,r10} 208 209 LDMFD r13!,{r10,PC} 210adv_end: 211 MOV r2, #0 212 MOV r12,#0 213 STMIA r0,{r2,r3,r12} 214 215 LDMFD r13!,{r10,PC} 216 217oggpack_readinit: 218 @ r0 = oggpack_buffer *b 219 @ r1 = oggreference *r 220 STR r1,[r0,#12] @ b->head = r1 221 STR r1,[r0,#16] @ b->tail = r1 222 LDMIA r1,{r2,r3,r12} @ r2 = b->head->buffer 223 @ r3 = b->head->begin 224 @ r12= b->head->length 225 LDR r2,[r2] @ r2 = b->head->buffer->data 226 MOV r1,r12,LSL #3 @ r1 = BitsInSegment 227 MOV r12,#0 228 ADD r3,r2,r3 @ r3 = r2+b->head->begin 229 BIC r2,r3,#3 @ r2 = b->headptr (word) 230 AND r3,r3,#3 231 MOV r3,r3,LSL #3 232 RSB r3,r3,#32 @ r3 = BitsInWord 233 STMIA r0,{r1,r2,r3} 234 STR r12,[r0,#20] 235 BX LR 236 237oggpack_read: 238 @ r0 = oggpack_buffer *b 239 @ r1 = int bits 240 STMFD r13!,{r10,r11,r14} 241 LDMIA r0,{r2,r3,r12} 242 @ r2 = bitsLeftInSegment 243 @ r3 = ptr 244 @ r12= bitsLeftInWord 245 SUBS r2,r2,r1 @ bitsLeftinSegment -= bits 246 BLT read_slow @ Not enough bits in this segment for 247 @ this request. Do it slowly. 248 LDR r10,[r3] @ r10= ptr[0] 249 RSB r14,r12,#32 @ r14= 32-bitsLeftInWord 250 SUBS r12,r12,r1 @ r12= bitsLeftInWord -= bits 251 ADDLE r3,r3,#4 252 LDRLT r11,[r3] @ r11= ptr[1] 253 MOV r10,r10,LSR r14 @ r10= ptr[0]>>(32-bitsLeftInWord) 254 ADDLE r12,r12,#32 @ r12= bitsLeftInWord += 32 255 RSB r14,r14,#32 @ r14= 32-bitsLeftInWord 256 ORRLT r10,r10,r11,LSL r14 @ r10= Next 32 bits. 257 STMIA r0,{r2,r3,r12} 258 MOV r14,#1 259 RSB r14,r14,r14,LSL r1 260 AND r0,r10,r14 261 LDMFD r13!,{r10,r11,PC} 262 263read_slow: 264 STMFD r13!,{r5,r6} 265 ADDS r10,r2,r1 @ r10= bitsLeftInSegment + bits (i.e. 266 @ the initial value of bitsLeftInSeg) 267 @ r10 = bitsLeftInSegment (initial) 268 @ r12 = bitsLeftInWord 269 RSB r14,r12,#32 @ r14= 32-bitsLeftInWord 270 MOV r5,r10 @ r5 = bitsLeftInSegment (initial) 271 BLT read_overrun 272 BEQ read_next_segment @ r10= r12 = 0, if we branch 273 CMP r12,r10 @ If bitsLeftInWord < bitsLeftInSeg 274 @ there must be more in the next word 275 LDR r10,[r3],#4 @ r10= ptr[0] 276 LDRLT r6,[r3] @ r6 = ptr[1] 277 MOV r11,#1 278 MOV r10,r10,LSR r14 @ r10= first bitsLeftInWord bits 279 ORRLT r10,r10,r6,LSL r12 @ r10= first bitsLeftInSeg bits+crap 280 RSB r11,r11,r11,LSL r5 @ r11= mask 281 AND r10,r10,r11 @ r10= first r5 bits 282 @ Load the next segments data 283read_next_segment: 284 @ At this point, r10 contains the first r5 bits of the result 285 LDR r11,[r0,#12] @ r11= head = b->head 286 @ Stall 287read_next_segment_2: 288 @ r11 = head 289 LDR r6,[r0,#20] @ r6 = count 290 LDR r12,[r11,#8] @ r12= length 291 LDR r11,[r11,#12] @ r11= head = head->next 292 @ Stall 293 ADD r6,r6,r12 @ count += length 294 CMP r11,#0 295 BEQ read_out_of_data 296 STR r11,[r0,#12] 297 STR r6,[r0,#20] @ b->count = count 298 LDMIA r11,{r6,r12,r14} @ r6 = buffer 299 @ r12= begin 300 @ r14= length 301 LDR r6,[r6] @ r6 = buffer->data 302 CMP r14,#0 303 BEQ read_next_segment_2 304 ADD r6,r6,r12 @ r6 = buffer->data+begin 305read_slow_loop: 306 LDRB r12,[r6],#1 @ r12= *buffer 307 SUBS r14,r14,#1 @ r14= length 308 @ Stall 309 ORR r10,r10,r12,LSL r5 @ r10= first r5+8 bits 310 ADD r5,r5,#8 311 BLE read_really_slow 312 CMP r5,r1 313 BLT read_slow_loop 314read_end: 315 MOV r12,#1 316 RSB r12,r12,r12,LSL r1 317 318 @ Store back the new position 319 @ r2 = -number of bits to go from this segment 320 @ r6 = ptr 321 @ r14= bytesLeftInSegment 322 @ r11= New head value 323 LDMIA r11,{r3,r6,r14} @ r3 = buffer 324 @ r6 = begin 325 @ r14= length 326 LDR r3,[r3] @ r3 = buffer->data 327 ADD r1,r2,r14,LSL #3 @ r1 = bitsLeftInSegment 328 @ stall 329 ADD r6,r3,r6 @ r6 = pointer 330 AND r3,r6,#3 @ r3 = bytes used in first word 331 RSB r3,r2,r3,LSL #3 @ r3 = bits used in first word 332 BIC r2,r6,#3 @ r2 = word ptr 333 RSBS r3,r3,#32 @ r3 = bitsLeftInWord 334 ADDLE r3,r3,#32 335 ADDLE r2,r2,#4 336 STMIA r0,{r1,r2,r3} 337 338 AND r0,r10,r12 339 LDMFD r13!,{r5,r6,r10,r11,PC} 340 341 342read_really_slow: 343 CMP r5,r1 344 BGE read_end 345 LDR r14,[r11,#8] @ r14= length of segment just done 346 @ stall 347 @ stall 348 ADD r2,r2,r14,LSL #3 @ r2 = -bits to use from next seg 349 B read_next_segment_2 350 351read_out_of_data: 352 @ Store back the new position 353 @ r2 = -number of bits to go from this segment 354 @ r6 = ptr 355 @ r14= bytesLeftInSegment 356 @ RJW: This may be overkill - we leave the buffer empty, with -1 357 @ bits left in it. We might get away with just storing the 358 @ bitsLeftInSegment as -1. 359 LDR r11,[r0,#12] @ r11=head 360 361 LDMIA r11,{r3,r6,r14} @ r3 = buffer 362 @ r6 = begin 363 @ r14= length 364 LDR r3,[r3] @ r3 = buffer->data 365 ADD r6,r3,r6 @ r6 = pointer 366 ADD r6,r6,r14 367 AND r3,r6,#3 @ r3 = bytes used in first word 368 MOV r3,r3,LSL #3 @ r3 = bits used in first word 369 BIC r2,r6,#3 @ r2 = word ptr 370 RSBS r3,r3,#32 @ r3 = bitsLeftInWord 371 MVN r1,#0 @ r1 = -1 = bitsLeftInSegment 372 STMIA r0,{r1,r2,r3} 373 @MVN r0,#0 ; return -1 374 MOV r0,#0 375 LDMFD r13!,{r5,r6,r10,r11,PC} 376 377read_overrun: 378 @ We had overrun when we started, so we need to skip -r10 bits. 379 LDR r11,[r0,#12] @ r11 = head = b->head 380 @ stall 381 @ stall 382read_overrun_next_segment: 383 LDR r11,[r11,#12] @ r11 = head->next 384 @ stall 385 @ stall 386 CMP r11,#0 387 BEQ read_out_of_data 388 LDMIA r11,{r6,r7,r14} @ r6 = buffer 389 @ r7 = begin 390 @ r14= length 391 LDR r6,[r6] @ r6 = buffer->data 392 @ stall 393 @ stall 394 ADD r6,r6,r7 @ r6 = buffer->data+begin 395 MOV r14,r14,LSL #3 @ r14= length in bits 396 ADDS r14,r14,r10 @ r14= length in bits-bits to skip 397 MOVLE r10,r14 398 BLE read_overrun_next_segment 399 RSB r10,r10,#0 @ r10= bits to skip 400 ADD r6,r10,r10,LSR #3 @ r6 = pointer to data 401 MOV r10,#0 402 B read_slow_loop 403 404 @ END 405