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 oggpack_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 66 look_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 86 look_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 91 look_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 104 look_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 119 look_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 127 look_out_of_data: 128 @MVN r0,#0 ; return -1 129 MOV r0,#0 130 LDMFD r13!,{r5,r6,r10,r11,PC} 131 132 look_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 137 look_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 159 oggpack_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 173 adv_slow: 174 STMFD r13!,{r10,r14} 175 176 LDR r14,[r0,#12] @ r14= head 177 @ stall 178 adv_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} 205 adv_end: 206 MOV r2, #0 207 MOV r12,#0 208 STMIA r0,{r2,r3,r12} 209 210 LDMFD r13!,{r10,PC} 211 212 oggpack_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 232 oggpack_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 258 read_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 278 read_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 282 read_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 300 read_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 309 read_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 337 read_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 346 read_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 372 read_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 377 read_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