1#include <arm/arch.h> 2 3// the follow assembly code was hard wired to POSTINC not defined, 4 5#if 0 // #ifdef POSTINC 6# define OFF 0 7# define PUP(a) *(a)++ 8#else 9# define OFF 1 10# define PUP(a) *++(a) 11#endif 12 13// the code uses r9, therefore, it does not meet the register protocol for armv5 and below 14// the code can only be used for armv6 and above 15 16#if defined _ARM_ARCH_6 17 18 .cstring 19 .align 2 20LC0: 21 .ascii "invalid distance too far back\0" 22 .align 2 23LC1: 24 .ascii "invalid distance code\0" 25 .align 2 26LC2: 27 .ascii "invalid literal/length code\0" 28 29 // renaming the register and stack memory use 30 31 #define out r0 32 #define strm r10 33 #define state r5 34 #define in r11 35 #define write r9 36 #define distcode r8 37 #define bits lr 38 #define hold r4 39 40 // stack memory allocation 41 42 #define window_loc [sp,#0] 43 #define last_loc [sp,#4] 44 #define beg_loc [sp,#8] 45 #define end_loc [sp,#12] 46 #define wsize_loc [sp,#16] 47 #define whave_loc [sp,#20] 48 #define windowm1_loc [sp,#28] 49 #define lmask_loc [sp,#32] 50 #define dmask_loc [sp,#36] 51 #define op_loc [sp,#44] 52 #define dist_loc [sp,#48] 53 54 #define local_size 52 55 56 // the following defines the variable offset in the inflate_state structure (in inflate.h) 57 58 #define state_mode [state, #0] 59 #define state_last [state, #4] 60 #define state_wrap [state, #8] 61 #define state_havedict [state, #12] 62 #define state_flags [state, #16] 63 #define state_dmax [state, #20] 64 #define state_wbits [state, #36] 65 #define state_wsize [state, #40] 66 #define state_whave [state, #44] 67 #define state_write [state, #48] 68 #define state_window [state, #52] 69 #define state_hold [state, #56] 70 #define state_bits [state, #60] 71 #define state_lencode [state, #76] 72 #define state_distcode [state, #80] 73 #define state_lenbits [state, #84] 74 #define state_distbits [state, #88] 75 76 77// void inflate_fast(z_streamp strm, unsigned start) 78// input : 79// r0 = strm, (move to r10) 80// r1 = start 81 82 .text 83 .align 2 84 .globl _inflate_fast 85_inflate_fast: 86 87 stmfd sp!, {r4-r6,r8-r11,lr} 88 sub sp, sp, #local_size 89 90#if defined(_ARM_ARCH_5) 91 ldrd r2,r3,[r0, #0] // r2 = strm->next_in, r3 = strm->avail_in 92#else 93 ldmia r0, {r2-r3} 94#endif 95 96 sub in, r2, #OFF // in = strm->next_in - OFF; 97 sub r2, #(OFF+5) // next_in -= (OFF+5); 98 ldr state, [r0, #28] // state = (struct inflate_state FAR *)strm->state; 99 add r3, r3, r2 // last = next_in - OFF + (avail_in - 5); next_in already updated 100 mov strm, r0 101 str r3, last_loc // store last to release r3 102 103 ldr r3, [r0, #12] // next_out 104 ldr r2, [strm, #16] // avail_out 105 106 sub out, r3, #OFF // out = strm->next_out - OFF; r0 is used as out from this point on 107 108 sub r3, r3, #256 // next_out - 256 109 rsb r1, r2, r1 // start - avail_out 110 sub r3, r3, #(1+OFF) // next_out-OFF-257 111 add r3, r3, r2 // r3 = end = avail_out + (next_out-OFF) - 257 = avail_out + out - 257 112 rsb r2, r1, out // r2 = beg = out - (start - avail_out); 113#if defined(_ARM_ARCH_5) 114 strd r2,r3, beg_loc // store beg/end 115 ldrd r2,r3, state_wsize // wsize/whave 116 strd r2,r3, wsize_loc // store wsize/whave 117 //ldrd r6,hold, state_window // window/hold, hold use r7 118 ldr r6, state_window // state->window 119 ldr hold, state_hold // state->hold 120 nop 121#else 122 // for architecture < armv5, ldrd/strd is not available 123 str r2, beg_loc // store beg 124 str r3, end_loc // store end 125 ldr r2, state_wsize // state->wsize 126 ldr r3, state_whave // state->whave 127 str r2, wsize_loc // store wsize 128 str r3, whave_loc // store whave 129 ldr r6, state_window // state->window 130 ldr hold, state_hold // state->hold 131#endif 132 133 ldr ip, state_lencode // lencode 134 mov r3, #1 // used to derive lmask and dmask 135 ldr write, state_write // write (r9 from this point on) : window write index 136 nop 137 str ip, [sp, #40] // save lencode 138 sub ip, r6, #1 // window-1 139 str r6, window_loc // store window 140 str ip, windowm1_loc // store window-1 141 ldr r2, state_lenbits // lenbits 142 ldr bits, state_bits // bits, use lr from this point on 143 ldr distcode, state_distcode// distcode, use r8 144 mov r2, r3, asl r2 // (1<<lensbits) 145 ldr r12, state_distbits // distbits 146 sub r2, r2, #1 // lmask = (1U << state->lenbits) - 1; 147 mov r3, r3, asl r12 // (1U << state->distbits) 148 sub r3, r3, #1 // dmask = (1U << state->distbits) - 1; 149 150#if defined(_ARM_ARCH_5) 151 strd r2, r3, lmask_loc // store lmask/dmask 152#else 153 str r2, lmask_loc // lmask 154 str r3, dmask_loc // dmask 155#endif 156 157 // start the do loop decoding literals and length/distances 158 // until end-of-block or not enough input data or output spaaaaaace 159 160do_loop: 161 cmp bits, #15 // bits vs 15 162 ldr r1, lmask_loc // lmask 163 bge bitsge15 // if bits >= 15, skip loading new 16 bits 164 165 // this is a shortcut with the processor reads data in little-endian mode 166 ldrh r3, [in,#1] // read 2 bytes 167 add in, #2 // in pointer += 2 168 add hold, hold, r3, asl bits // deposit the new 2 bytes into hold 169 add bits, #16 // bits count += 16 170 171bitsge15: 172 ldr ip, [sp, #40] // restore lencode 173 and r3, hold, r1 // r3 = hold & lmask 174 b dolen 175 176op_not_zero: 177 178 tst r2, #16 // if (op&16) 179 bne length_base // branch to length_base 180 181 tst r2, #64 // else if (op&64) 182 bne end_of_block // branch to end_of_block processing 183 184 // 2nd-level length code, this is the part where if ((op & 64) == 0) { ... } 185 186 // this.val + (hold & ((1U << op) - 1)); 187 // r3 = r1 + hold & ((1<<r2)-1); 188 189 rsb r12, r2, #32 // r12 = (32-op) 190 ror r3, hold, r2 // rotate the op least significant bits of hold to MSB 191 add r3, r1, r3, lsr r12 // r3 = r1 + (op LSBs in hold) = r1 + hold & ((1<<r2)-1); 192 193 ldr ip, [sp, #40] // restore lencode 194 195dolen: 196 197 // code -> 8-bit code, 8-bit bits, 16-bit val 198 ldrb r2, [ip,r3,asl #2] // op = (unsigned)(this.bits); 199 add r3, ip, r3, asl #2 // r3 = this 200 ldrb ip, [r3, #1] // ip = this.bits 201 ldrh r1, [r3, #2] // r1 = this.value 202 cmp r2, #0 // op == 0 ? 203 204 mov hold, hold, lsr ip // hold >>= this.bits 205 rsb bits, ip, bits // bits -= this.bits 206 bne op_not_zero // branch to op_not_zero if this.op != 0 207 208 strb r1, [out, #1]! // PUP(out) = (unsigned char)(this.val); 209 210do_loop_while: 211 ldr r1, last_loc // last 212 ldr r2, end_loc // end 213 cmp in, r1 // compare in vs last 214 cmpcc out, r2 // if in < last, compare out vs end 215 bcc do_loop // if (in < last && out < end) go back to do_loop 216 217update_state_and_return: 218 219 sub r2, in, bits, lsr #3 // r2 = in - (bits>>3) 220 221 add r3, r2, #OFF // r3 = (in - (bits>>3)) + OFF 222 str r3, [strm, #0] // strm->next_in = in + OFF; 223 224 add r3, out, #OFF // out + OFF 225 str r3, [strm, #12] // strm->next_out = out + OFF; 226 227 ldr r3, last_loc // r3 = last 228 ldr ip, end_loc // ip = end 229 230 cmp r3, r2 // compare last vs in 231 addhi r3, r3, #5 // if last > in, last +=5 232 movls r6, r3 // o.w., r6 = last 233 rsbls r3, r6, r2 // r3 = in-last 234 rsbhi r3, r2, r3 // r3 = (last+5) - in 235 rsbls r3, r3, #5 // r3 = 5 - (in-last); 236 cmp out, ip // compare out vs end 237 str r3, [strm, #4] // strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); 238 movcs r2, ip // if out<end, r2=end 239 addcc r3, ip, #256 // if out>=end, r3 = end+256 240 rsbcs r3, r2, out // if out<end, r3 = out-end 241 addcc r3, r3, #1 // if out>=end, r3 = end+257 242 rsbcs r3, r3, #256 // if out<end, r3 = 256-(out-end) = 256 + (end-out) 243 and bits, #7 // this is equivalent to bits -= (bits>>3) << 3; 244 rsbcc r3, out, r3 // if out<end, r3 = 257+end-out 245 addcs r3, r3, #1 // if out>=end, r3 = 257 + (end-out) 246 str r3, [strm, #16] // strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); 247 248 // hold &= (1U << bits) - 1; 249 250 rsb ip, bits, #32 // 32-bits 251 ror hold, hold, bits // this is equivalent to hold<<(32-bits) 252 lsr hold, hold, ip // logical shift right by (32-bits), hold now only keeps the bits LSBs 253 254 str bits, state_bits // state->bits = bits; 255 str hold, state_hold // state->hold = hold; 256 257 add sp, #local_size // pop out stack memory 258 ldmfd sp!,{r4-r6,r8-r11,pc} // restore registers and return 259 260length_base: // r2=op, r1=lmask 261 ands r2, r2, #15 // op&=15; 262 mov r6, r1 // len = (unsigned) this.val; 263 beq op_is_zero // if op==0, branch to op_is_zero 264 cmp r2, bits // op vs bits 265 ldrbhi r3, [in, #1]! // if (op>bits) r3 = (PUP(in)); 266 addhi hold, hold, r3, asl bits // if (op>bits) hold += (unsigned long)(PUP(in)) << bits; 267 268 rsb ip, r2, #32 // 32-op 269 ror r3, hold, r2 // (hold<<(32-op)) 270 add r6, r1, r3, lsr ip // len += (unsigned)hold & ((1U << op) - 1); 271 272 addhi bits, bits, #8 // if (op>bits) bits += 8; 273 274 mov hold, hold, lsr r2 // hold >>= op; 275 rsb bits, r2, bits // bits -= op; 276 277op_is_zero: 278 cmp bits, #14 279 ldrh r3,[in,#1] // if (bits < 15) { 2 (PUP(in)); no condition code for better performance 280 addls in, #2 // in+=2; 281 addls hold, hold, r3, asl bits // twice hold += (unsigned long)(PUP(in)) << bits; 282 addls bits, #16 // 2 bits += 8; } 283 284dodist: 285 286 ldr r2, dmask_loc // r2 = dmask 287 and r3, hold, r2 // r3 = hold & dmask 288 mov r2, r3, asl #2 289 add r3, r2, distcode // &dcode[hold&dmask]; 290 ldrb ip, [r2, distcode] // op 291 ldrh r1, [r3, #2] // dist = (unsigned)(this.val); 292 tst ip, #16 // op vs 16 293 ldrb r3, [r3, #1] // this.bits 294 mov hold, hold, lsr r3 // hold >>= this.bits; 295 rsb bits, r3, bits // bits -= this.bits; 296 bne distance_base // if (op&16) { distance base processing } 297 tst ip, #64 // 298 beq second_distance_code // else if ((op&64)==0) branch to 2nd level distance code 299 300 b invalide_distance_code 301 302check_2nd_level_distance_code: 303 304 tst r2, #64 // check for esle if ((op & 64) == 0) for 2nd level distance code 305 bne invalide_distance_code 306 307second_distance_code: 308 309 rsb r2, ip, #32 // 32-op 310 ror r3, hold, ip // hold<<(32-op) 311 add r3, r1, r3, lsr r2 // this.val + (hold & ((1U << op) - 1)) 312 313 mov r2, r3, asl #2 314 add r3, r2, distcode // this = dcode[this.val + (hold & ((1U << op) - 1))]; 315 ldrb r2, [r2, distcode] // this.op 316 ldrh r1, [r3, #2] // this.val 317 318 tst r2, #16 // op&16 319 ldrb r3, [r3, #1] // this.bits 320 mov ip, r2 // op 321 mov hold, hold, lsr r3 // hold >> = this.bits 322 rsb bits, r3, bits // bits -= this.bits 323 beq check_2nd_level_distance_code 324 325distance_base: // this is invoked from if ((op&16)!=0) 326 327 and r2, ip, #15 // op &= 15; 328 cmp r2, bits // op vs bits 329 ldrbhi r3, [in, #1]! // if (op > bits) (PUP(in)) 330 addhi hold, hold, r3, asl bits // hold += (unsigned long)(PUP(in)) << bits; 331 addhi bits, bits, #8 // bits += 8; 332 cmphi r2, bits // internel (bits < op) 333 ldrbhi r3, [in, #1]! // if (op > bits) (PUP(in)) 334 addhi hold, hold, r3, asl bits // hold += (unsigned long)(PUP(in)) << bits; 335 addhi bits, bits, #8 // bits += 8 336 337 rsb ip, r2, #32 // (32-op) 338 ror r3, hold, r2 // hold<<(32-op) 339 add r3, r1, r3, lsr ip // dist += (unsigned)hold & ((1U << op) - 1); 340 str r3, dist_loc // save dist 341 342 343#ifdef INFLATE_STRICT 344 ldr r1, state_dmax // r1 = dmax 345 cmp r3, r1 // dist vs dmax 346 bgt invalid_distance_too_far_back // if dist > dmax, set up msg/mode = bad and break 347#endif 348 349 mov hold, hold, lsr r2 // hold >>= op ; 350 rsb bits, r2, bits // bits -= op; 351 352 ldr ip, beg_loc // beg 353 ldr r1, dist_loc // dist 354 rsb r3, ip, out // (out - beg); 355 356 cmp r1, r3 // dist vs (out - beg) 357 358 rsbls r2, r1, out // if (dist<=op) r2 = from = out-dist 359 bls copy_direct_from_output // if (dist<=op) branch to copy_direct_from_output 360 361 ldr r2, whave_loc // whave 362 rsb r1, r3, r1 // op = dist-op 363 cmp r2, r1 // whave vs op 364 str r1, op_loc // save a copy of op 365 bcc invalid_distance_too_far_back // if whave < op, message invalid distance too far back, and break 366 367 cmp write, #0 // write 368 bne non_very_common_case // if (write ==0) non_very_common_case 369 370 // the following : if (write == 0) { /* very common case */ } 371 ldr r1, op_loc // restore op in r1 372 ldr ip, wsize_loc // wsize 373 cmp r6, r1 // len vs op 374 rsb r3, r1, ip // wsize - op 375 ldr ip, windowm1_loc // window - 1 376 add r2, ip, r3 // from = window - 1 + wsize - op : setup for using PUP(from) 377 //movhi r3, r1 // if len > op, r3 = op 378 //movhi r1, out // if len > op, r1 = out 379 bhi some_from_window // if (len > op), branch to some_from_window 380 381finish_copy: 382 383 // while (len > 2) { 384 // PUP(out) = PUP(from); 385 // PUP(out) = PUP(from); 386 // PUP(out) = PUP(from); 387 // len -= 3; 388 // } 389 // if (len) { 390 // PUP(out) = PUP(from); 391 // if (len > 1) 392 // PUP(out) = PUP(from); 393 // } 394 395 cmp r6, #2 // len > 2 ? 396 movls r1, r6 // if (len<=2) r1 = len 397 bls lenle2 // if (len<=2) branch to lenle2 398 mov r1, r6 399fcopy_per3bytes: 400 ldrb r3, [r2, #1] // 1st PUP(from) 401 sub r1, r1, #3 // len-=3 402 cmp r1, #2 // len > 2 ? 403 strb r3, [out, #1] // 1st PUP(out) = PUP(from); 404 ldrb r3, [r2, #2] // 2nd PUP(from) 405 add r2, r2, #3 // from+=3 406 strb r3, [out, #2] // 2nd PUP(out) = PUP(from); 407 ldrb r3, [r2, #0] // 3rd PUP(from) 408 add out, out, #3 // out+=3 409 strb r3, [out, #0] // 3rd PUP(out) = PUP(from); 410 bgt fcopy_per3bytes // while (len>3) back to loop head 411lenle2: 412 cmp r1, #0 // len 413 beq do_loop_while // back to while loop head if len==0 414 ldrb r3, [r2, #1] // PUP(from) 415 cmp r1, #2 // check whether len==2 416 strb r3, [out, #1]! // PUP(out) = PUP(from); 417 bne do_loop_while // back to while loop head if len==1 418 ldrb r3, [r2, #2] // 2nd PUP(from) 419 strb r3, [out, #1]! // 2nd PUP(out) = PUP(from); 420 b do_loop_while // back to while loop head 421 422end_of_block: 423 tst r2, #32 // if (op&32) 424 movne r3, #11 // TYPE? 425 strne r3, state_mode // state-mode = TYPE 426 bne update_state_and_return // break the do loop and branch to get ready to return 427 ldr r3, messages // "invalid literal/length code" message 428L75: 429 add r3, pc, r3 430 str r3, [strm, #24] // strm->msg = (char *)"invalid literal/length code"; 431 mov r3, #27 // BAD? 432 str r3, state_mode // state->mode = BAD; 433 b update_state_and_return // break the do loop and branch to get ready to return 434 435//Read_2_bytes: 436// ldrh r3,[in,#1] // 2 (PUP(in)) together 437// add in, #2 // 2 in++ 438// add hold, hold, r3, asl bits // twice hold += (unsigned long)(PUP(in)) << bits; 439// add bits, #16 // 2 bits += 8; 440// b dodist // branch to dodist 441 nop // a pad dummy instruction to give better performance 442 443copy_direct_from_output: // r2 = from = out - dist ; 444 445 // do { 446 ldrb r3, [r2, #1] // 1st PUP(from) 447 sub r6, r6, #3 // len-=3 448 cmp r6, #2 // len vs 2 449 strb r3, [out, #1] // 1st PUP(out) = PUP(from); 450 ldrb r3, [r2, #2] // 2nd PUP(from) 451 add r2, r2, #3 // update from+=3 452 strb r3, [out, #2] // 2nd PUP(out) = PUP(from); 453 ldrb r3, [r2, #0] // 3rd PUP(from); 454 add out, out, #3 // update out+=3 455 strb r3, [out, #0] // 3rd PUP(out) = PUP(from); 456 bhi copy_direct_from_output // while (len>2); 457 458 // len in r6 can now be 0 1 or 2 459 460 subs r6,#1 // len--; 461 ldrb r3, [r2, #1] // PUP(from) 462 blt do_loop_while // if len<0 back to while loop head 463 strb r3, [out, #1]! // PUP(out) = PUP(from); 464 subs r6, #1 // len--; 465 ldrb r3, [r2, #2] // 2nd PUP(from) 466 blt do_loop_while // if len<0 back to while loop head 467 strb r3, [out, #1]! // 2nd PUP(out) = PUP(from); 468 b do_loop_while // back to while loop head 469 470 471invalide_distance_code: 472 ldr r3, messages+4 // "invalid distance code" 473L72: 474 add r3, pc, r3 475 str r3, [strm, #24] // strm->msg = (char *)"invalid distance code"; 476 mov r3, #27 477 str r3, state_mode // state->mode = BAD; 478 b update_state_and_return // break, restore registers, and return 479 480 481some_from_window: 482 ldr r3, dist_loc // dist 483 rsb r6, r1, r6 // len -= op 484some_from_window_loop: // do { 485 ldrb ip, [r2, #1]! // PUP(from); 486 subs r1, #1 // --op 487 strb ip, [out, #1]! // PUP(out) = PUP(from); 488 bne some_from_window_loop // } while(op); 489 rsb r2, r3, out // from = out - dist; 490 b finish_copy 491 492non_very_common_case: 493 ldr r1, op_loc // restore op in r1 494 cmp write, r1 // write vs op 495 bcs contiguous_in_window // if (write >= op) branch to contiguous_in_window 496 497 /* wrap around window */ 498 499 ldr r2, wsize_loc // wsize 500 ldr ip, windowm1_loc // window-1 501 add r3, write, r2 // r3 = wsize+write 502 rsb r3, r1, r3 // r3 = wsize+write-op 503 add r2, ip, r3 // r2 = from = wsize+write-op+window-1; 504 rsb r1, write, r1 // op -= write; 505 506 cmp r6, r1 // len vs op 507 bls finish_copy // if (len <= op) branch to finish_copy 508 rsb r6, r1, r6 // len -= op 509waw_loop: // do { 510 ldrb r3, [r2, #1]! // PUP(from) 511 subs r1, r1, #1 // --op; 512 strb r3, [out, #1]! // PUP(out) = PUP(from); 513 bne waw_loop // } while (op); 514 515 cmp write, r6 // write vs len 516 ldr r2, windowm1_loc // if (write>=len) r2 = from = window-1; 517 bcs finish_copy // if (write>=len) branch to finish_copy 518 519 // some from start of window 520 521 mov r1, write // op = write 522 sub r6, write // len -= op 523sow_loop: // do { 524 ldrb r3,[r2, #1]! // PUP(from) 525 subs r1, #1 // --op; 526 strb r3, [out,#1]! // PUP(out) = PUP(from); 527 bne sow_loop // } while (op); 528 529 ldr r2, dist_loc // dist 530 rsb r2, r2, out // r2 = from = out-dist 531 b finish_copy // continue to finish_copy 532 533 534contiguous_in_window: 535 ldr ip, windowm1_loc // window-1 536 cmp r6, r1 // len vs op 537 rsb r3, r1, write // r3 = write-op 538 add r2, ip, r3 // r2 = from = window+write-op-1 539 bls finish_copy // if (len <= op) branch to finish_copy 540 rsb r6, r1, r6 // len -= op 541 ldr r3, dist_loc // dist 542ciw_loop: 543 ldrb ip, [r2, #1]! // PUP(from) 544 subs r1, r1, #1 // op-- 545 strb ip, [out, #1]! // PUP(out) = PUP(from); 546 bne ciw_loop // while (--op); 547 rsb r2, r3, out // from = out - dist; 548 b finish_copy 549 550invalid_distance_too_far_back: 551 ldr r3, messages+8 // "invalid distance too far back" 552L42: 553 add r3, pc, r3 554 str r3, [strm, #24] // strm->msg = (char *)"invalid distance too far back"; 555 mov r3, #27 556 str r3, state_mode // state->mode = BAD; 557 b update_state_and_return // break, restore registers, and return 558 559 .align 2 560messages: 561 .long LC2-8-(L75) 562 .long LC1-8-(L72) 563 .long LC0-8-(L42) 564 565#endif // defined _ARM_ARCH_6 566