3 // the follow assembly code was hard wired to POSTINC not defined,
5 #if 0 // #ifdef POSTINC
10 # define PUP(a) *++(a)
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
16 #if defined _ARM_ARCH_6
21 .ascii "invalid distance too far back\0"
24 .ascii "invalid distance code\0"
27 .ascii "invalid literal/length code\0"
29 // renaming the register and stack memory use
40 // stack memory allocation
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]
56 // the following defines the variable offset in the inflate_state structure (in inflate.h)
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]
77 // void inflate_fast(z_streamp strm, unsigned start)
79 // r0 = strm, (move to r10)
87 stmfd sp!, {r4-r6,r8-r11,lr}
88 sub sp, sp, #local_size
90 #if defined(_ARM_ARCH_5)
91 ldrd r2,r3,[r0, #0] // r2 = strm->next_in, r3 = strm->avail_in
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
101 str r3, last_loc // store last to release r3
103 ldr r3, [r0, #12] // next_out
104 ldr r2, [strm, #16] // avail_out
106 sub out, r3, #OFF // out = strm->next_out - OFF; r0 is used as out from this point on
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
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
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
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;
150 #if defined(_ARM_ARCH_5)
151 strd r2, r3, lmask_loc // store lmask/dmask
153 str r2, lmask_loc // lmask
154 str r3, dmask_loc // dmask
157 // start the do loop decoding literals and length/distances
158 // until end-of-block or not enough input data or output space
161 cmp bits, #15 // bits vs 15
162 ldr r1, lmask_loc // lmask
163 bge bitsge15 // if bits >= 15, skip loading new 16 bits
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
172 ldr ip, [sp, #40] // restore lencode
173 and r3, hold, r1 // r3 = hold & lmask
178 tst r2, #16 // if (op&16)
179 bne length_base // branch to length_base
181 tst r2, #64 // else if (op&64)
182 bne end_of_block // branch to end_of_block processing
184 // 2nd-level length code, this is the part where if ((op & 64) == 0) { ... }
186 // this.val + (hold & ((1U << op) - 1));
187 // r3 = r1 + hold & ((1<<r2)-1);
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);
193 ldr ip, [sp, #40] // restore lencode
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 ?
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
208 strb r1, [out, #1]! // PUP(out) = (unsigned char)(this.val);
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
217 update_state_and_return:
219 sub r2, in, bits, lsr #3 // r2 = in - (bits>>3)
221 add r3, r2, #OFF // r3 = (in - (bits>>3)) + OFF
222 str r3, [strm, #0] // strm->next_in = in + OFF;
224 add r3, out, #OFF // out + OFF
225 str r3, [strm, #12] // strm->next_out = out + OFF;
227 ldr r3, last_loc // r3 = last
228 ldr ip, end_loc // ip = end
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));
248 // hold &= (1U << bits) - 1;
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
254 str bits, state_bits // state->bits = bits;
255 str hold, state_hold // state->hold = hold;
257 add sp, #local_size // pop out stack memory
258 ldmfd sp!,{r4-r6,r8-r11,pc} // restore registers and return
260 length_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 ldrhib 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;
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);
272 addhi bits, bits, #8 // if (op>bits) bits += 8;
274 mov hold, hold, lsr r2 // hold >>= op;
275 rsb bits, r2, bits // bits -= op;
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; }
286 ldr r2, dmask_loc // r2 = dmask
287 and r3, hold, r2 // r3 = hold & dmask
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 }
298 beq second_distance_code // else if ((op&64)==0) branch to 2nd level distance code
300 b invalide_distance_code
302 check_2nd_level_distance_code:
304 tst r2, #64 // check for esle if ((op & 64) == 0) for 2nd level distance code
305 bne invalide_distance_code
307 second_distance_code:
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))
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
319 ldrb r3, [r3, #1] // this.bits
321 mov hold, hold, lsr r3 // hold >> = this.bits
322 rsb bits, r3, bits // bits -= this.bits
323 beq check_2nd_level_distance_code
325 distance_base: // this is invoked from if ((op&16)!=0)
327 and r2, ip, #15 // op &= 15;
328 cmp r2, bits // op vs bits
329 ldrhib 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 ldrhib 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
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
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
349 mov hold, hold, lsr r2 // hold >>= op ;
350 rsb bits, r2, bits // bits -= op;
352 ldr ip, beg_loc // beg
353 ldr r1, dist_loc // dist
354 rsb r3, ip, out // (out - beg);
356 cmp r1, r3 // dist vs (out - beg)
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
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
367 cmp write, #0 // write
368 bne non_very_common_case // if (write ==0) non_very_common_case
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
384 // PUP(out) = PUP(from);
385 // PUP(out) = PUP(from);
386 // PUP(out) = PUP(from);
390 // PUP(out) = PUP(from);
392 // PUP(out) = PUP(from);
395 cmp r6, #2 // len > 2 ?
396 movls r1, r6 // if (len<=2) r1 = len
397 bls lenle2 // if (len<=2) branch to lenle2
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
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
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
430 str r3, [strm, #24] // strm->msg = (char *)"invalid literal/length code";
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
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
443 copy_direct_from_output: // r2 = from = out - dist ;
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);
458 // len in r6 can now be 0 1 or 2
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
471 invalide_distance_code:
472 ldr r3, messages+4 // "invalid distance code"
475 str r3, [strm, #24] // strm->msg = (char *)"invalid distance code";
477 str r3, state_mode // state->mode = BAD;
478 b update_state_and_return // break, restore registers, and return
482 ldr r3, dist_loc // dist
483 rsb r6, r1, r6 // len -= op
484 some_from_window_loop: // do {
485 ldrb ip, [r2, #1]! // PUP(from);
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;
492 non_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
497 /* wrap around window */
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;
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
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);
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
519 // some from start of window
521 mov r1, write // op = write
522 sub r6, write // len -= op
524 ldrb r3,[r2, #1]! // PUP(from)
526 strb r3, [out,#1]! // PUP(out) = PUP(from);
527 bne sow_loop // } while (op);
529 ldr r2, dist_loc // dist
530 rsb r2, r2, out // r2 = from = out-dist
531 b finish_copy // continue to finish_copy
534 contiguous_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
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;
550 invalid_distance_too_far_back:
551 ldr r3, messages+8 // "invalid distance too far back"
554 str r3, [strm, #24] // strm->msg = (char *)"invalid distance too far back";
556 str r3, state_mode // state->mode = BAD;
557 b update_state_and_return // break, restore registers, and return
565 #endif // defined _ARM_ARCH_6