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