1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MI
3   File:     mi_uncomp_stream.c
4 
5   Copyright 2003-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-18#$
14   $Rev: 8573 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro/mi/stream.h>
19 #include <nitro/mi/uncompress.h>
20 #include <nitro/mi/uncomp_stream.h>
21 
22 // #define MI_USE_STRB
23 
24 /*---------------------------------------------------------------------------*
25   Name: MI_InitUncompContextRL
26 
27   Description: Initializes the streaming decompression context for run-length compressed data.
28 
29 
30   Arguments: context Pointer to the run-length uncompressed context
31                 dest        Destination address for uncompressed data
32                 header      Pointer to the start data for the compressed data
33 
34   Returns: Can get the data size after decompression.
35 
36  *---------------------------------------------------------------------------*/
MI_InitUncompContextRL(MIUncompContextRL * context,u8 * dest,const MICompressionHeader * header)37 void MI_InitUncompContextRL(MIUncompContextRL *context, u8 *dest, const MICompressionHeader *header)
38 {
39     context->destp = dest;
40     context->destCount = (s32)header->destSize;
41     context->flags = 0;
42     context->length = 0;
43     context->destTmp = 0;
44     context->destTmpCnt = 0;
45 }
46 
47 
48 /*---------------------------------------------------------------------------*
49   Name: MI_InitUncompContextLZ
50 
51   Description: Initializes the streaming decompression context for LZ-compressed data.
52 
53   Arguments: context Pointer to the LZ uncompressed context
54                 dest        Destination address for uncompressed data
55                 header      Pointer to the start data for the compressed data
56 
57  *---------------------------------------------------------------------------*/
MI_InitUncompContextLZ(MIUncompContextLZ * context,u8 * dest,const MICompressionHeader * header)58 void MI_InitUncompContextLZ(MIUncompContextLZ *context, u8 *dest, const MICompressionHeader *header)
59 {
60     context->destp = dest;
61     context->destCount = (s32)header->destSize;
62     context->flags = 0;
63     context->flagIndex = 0;
64     context->length = 0;
65     context->lengthFlg = 3;
66     context->destTmp = 0;
67     context->destTmpCnt = 0;
68     context->exFormat = (u8)( (header->compParam == 0)? 0U : 1U );
69 }
70 
71 
72 /*---------------------------------------------------------------------------*
73   Name: MI_InitUncompContextHuffman
74 
75   Description: Initializes the streaming decompression context for Huffman-compressed data.
76 
77   Arguments: context Pointer to the Huffman uncompressed context
78                 dest        Destination address for uncompressed data
79                 header      Pointer to the start data for the compressed data
80 
81  *---------------------------------------------------------------------------*/
MI_InitUncompContextHuffman(MIUncompContextHuffman * context,u8 * dest,const MICompressionHeader * header)82 void MI_InitUncompContextHuffman(MIUncompContextHuffman *context, u8 *dest,
83                                  const MICompressionHeader *header)
84 {
85     context->destp = dest;
86     context->destCount = (s32)header->destSize;
87     context->bitSize = (u8)header->compParam;
88     context->treeSize = -1;
89     context->treep = &context->tree[0];
90     context->destTmp = 0;
91     context->destTmpCnt = 0;
92     context->srcTmp = 0;
93     context->srcTmpCnt = 0;
94 }
95 
96 
97 //---- This code will be compiled in ARM-Mode
98 #include <nitro/code32.h>
99 /*---------------------------------------------------------------------------*
100   Name: MI_ReadUncompRL8
101 
102   Description: Performs streaming decompression of run-length compressed data.
103                 Data is written in units of 8 bits. Data cannot be directly uncompressed to VRAM.
104 
105   Arguments: context Pointer to the run-length uncompressed context
106                 data    Pointer to the next data
107                 len     Data size
108 
109   Returns: Size of remaining uncompressed data.
110 
111  *---------------------------------------------------------------------------*/
MI_ReadUncompRL8(register MIUncompContextRL * context,register const u8 * data,register u32 len)112 asm s32 MI_ReadUncompRL8( register MIUncompContextRL *context, register const u8* data, register u32 len )
113 {
114                 stmfd   sp!, {r4-r8}
115                                                                 // r0: context, r1: data, r2: len
116                 ldr     r3, [r0, #MIUncompContextRL.destp]      // r3: destp      = context->destp;
117                 ldr     r4, [r0, #MIUncompContextRL.destCount]  // r4: destCount  = context->destCount;
118                 ldrb    r5, [r0, #MIUncompContextRL.flags]      // r5: flags      = context->flags;
119                 ldrh    r6, [r0, #MIUncompContextRL.length]     // r6: length     = context->length
120 
121 @41:
122                 cmp     r4, #0          //  while ( destCount > 0 )
123                 ble     @49
124 
125                 tst     r5, #0x80       //     if ( ! flags & 0x80 ) {
126                 bne     @43
127 
128 @42:
129                 cmp     r6, #0          //          while ( length > 0 ) {
130                 ble     @45
131 
132                 sub     r6, r6, #1      //              length--;
133                 ldrb    r7, [r1], #1    //              *destp++ = *data++;
134                 sub     r4, r4, #1      //              destCount--;    // <- avoid pipe stall
135 #ifdef MI_USE_STRB
136                 strb    r7, [r3], #1
137 #else
138                 swpb    r8, r7,[r3]
139                 add     r3, r3, #1
140 #endif
141                 subs    r2, r2, #1      //              len--;
142                 beq     @49             //              if ( len == 0 ) { return destCount }
143                 b       @42             //          }
144 
145 @43:                                    //      } else if ( length > 0 ) {
146                 cmp     r6, #0
147                 ble     @45
148 
149                 ldrb    r7, [r1], #1    // r7:      srcTmp = *data++;
150 @44:                                    //          do {
151                 sub     r4, r4, #1      //              destCount--;    // <- avoid pipe stall
152 #ifdef MI_USE_STRB
153                 strb    r7, [r3], #1    //              *destp++ =  srcTmp;
154 #else
155                 swpb    r8, r7, [r3]
156                 add     r3, r3, #1
157 #endif
158                 subs    r6, r6, #1      //          } while ( --length > 0 )
159                 bgt     @44
160 
161                 subs    r2, r2, #1      //          len--;
162                 beq     @49             //          if ( len == 0 ) { return destCount }
163                                         //      }
164 @45:
165                 ldrb    r5, [r1], #1    //      flags = *data++;
166                 and     r6, r5, #0x7F   //      length = flags & 0x7F
167                 tst     r5, #0x80       //      if ( flags & 0x80 ) { length += 3 }
168                 addne   r6, r6, #2      //
169                 add     r6, r6, #1      //      else { length += 1 }
170 
171                 subs    r2, r2, #1      //      len--;
172                 bne     @41             //      if ( len == 0 ) { return destCount }
173                                         //  }
174 @49:
175                 str     r3, [r0, #MIUncompContextRL.destp]      // context->destp       = destp;
176                 str     r4, [r0, #MIUncompContextRL.destCount]  // context->destCount   = destCount;
177                 strb    r5, [r0, #MIUncompContextRL.flags]      // context->flags      = flags;
178                 strh    r6, [r0, #MIUncompContextRL.length]     // context->length     = length;
179                 mov     r0, r4
180 
181                 ldmfd   sp!, {r4-r8}
182                 bx      lr
183 }
184 
185 
186 /*---------------------------------------------------------------------------*
187   Name: MI_ReadUncompRL16
188 
189   Description: Performs streaming decompression of run-length compressed data.
190                 Data is written in 16-bit units. Data can be directly uncompressed to VRAM, but this is slower than MI_ReadUncompRL8.
191 
192 
193   Arguments: context Pointer to the run-length uncompressed context
194                 data    Pointer to the next data
195                 len     Data size
196 
197   Returns: Size of remaining uncompressed data.
198 
199  *---------------------------------------------------------------------------*/
MI_ReadUncompRL16(register MIUncompContextRL * context,register const u8 * data,register u32 len)200 asm s32 MI_ReadUncompRL16( register MIUncompContextRL *context, register const u8* data, register u32 len )
201 {
202                 stmfd   sp!, {r4-r9}
203                                                                 // r0: context, r1: data, r2: len
204                 ldr     r3, [r0, #MIUncompContextRL.destp]      // r3: destp      = context->destp;
205                 ldr     r4, [r0, #MIUncompContextRL.destCount]  // r4: destCount  = context->destCount;
206                 ldrb    r5, [r0, #MIUncompContextRL.flags]      // r5: flags      = context->flags;
207                 ldrh    r6, [r0, #MIUncompContextRL.length]     // r6: length     = context->length;
208                 ldrh    r7, [r0, #MIUncompContextRL.destTmp]    // r7: destTmp    = context->destTmp;
209                 ldrb    r8, [r0, #MIUncompContextRL.destTmpCnt] // r8: destTmpCnt = context->destTmpCnt;
210 
211 @41:
212                 cmp     r4, #0              //  while ( destCount > 0 )
213                 ble     @49
214 
215                 tst     r5, #0x80           //     if ( ! flags & 0x80 ) {
216                 bne     @44
217 
218 @42:
219                 cmp     r6, #0              //          while ( length > 0 ) {
220                 ble     @47
221 
222                 ldrb    r9, [r1], #1        //              destTmp |= (*data++) << destTmpCnt;
223                 sub     r6, r6, #1          //              length--;   // <- avoid pipe stall
224                 orr     r7, r7, r9, lsl r8
225                 add     r8, r8, #8          //              destTmpCnt += 8;
226                 cmp     r8, #16             //              if ( destTmpCnt == 16 ) {
227                 bne     @43
228                 strh    r7, [r3], #2        //                  *(u16*)destp = destTmp; destp += 2;
229                 mov     r7, #0              //                  destTmp = 0;
230                 mov     r8, #0              //                  destTmpCnt = 0;
231                 sub     r4, r4, #2          //                  destCount -= 2;
232 @43:                                        //              }
233                 subs    r2, r2, #1          //              len--;
234                 beq     @49                 //              if ( len == 0 ) { return destCount; }
235                 b       @42                 //          }
236 
237 @44:                                        //      } else if ( length > 0 ) {
238                 cmp     r6, #0
239                 ble     @47
240 
241                 ldrb    r9, [r1], #1        // r9:      srcTmp = *data++;
242 @45:                                        //          do {
243                 orr     r7, r7, r9, lsl r8  //              destTmp |= srcTmp << destTmpCnt;
244                 add     r8, r8, #8          //              destTmpCnt += 8;
245                 cmp     r8, #16             //              if ( destTmpCnt == 16 ) {
246                 bne     @46
247                 strh    r7, [r3], #2        //                  *(u16*)destp = destTmp; destp += 2;
248                 mov     r7, #0              //                  destTmp = 0;
249                 mov     r8, #0              //                  destTmpCnt = 0;
250                 sub     r4, r4, #2          //                  destCount -= 2;
251                                             //              }
252 @46:
253                 subs    r6, r6, #1          //          } while (--length > 0);
254                 bgt     @45
255 
256                 subs    r2, r2, #1          //          len--;
257                 beq     @49                 //          if ( len == 0 ) { return destCount; }
258                                             //      }
259 @47:
260                 ldrb    r5, [r1], #1        //      flags = *data++;
261                 and     r6, r5, #0x7F       //      length = flags & 0x7F
262                 tst     r5, #0x80           //      if ( flags & 0x80 ) { length += 3 }
263                 addne   r6, r6, #2          //
264                 add     r6, r6, #1          //      else { length += 1 }
265 
266                 subs    r2, r2, #1          //      len--;
267                 bne     @41                 //      if ( len == 0 ) { return destCount }
268                                             //  }
269 @49:
270                 str     r3, [r0, #MIUncompContextRL.destp]      // context->destp       = destp;
271                 str     r4, [r0, #MIUncompContextRL.destCount]  // context->destCount   = destCount;
272                 strb    r5, [r0, #MIUncompContextRL.flags]      // context->flags      = flags;
273                 strh    r6, [r0, #MIUncompContextRL.length]     // context->length     = length;
274                 strh    r7, [r0, #MIUncompContextRL.destTmp]    // context->destTmp     = destTmp;
275                 strb    r8, [r0, #MIUncompContextRL.destTmpCnt] // context->destTmpCnt = destTmpCnt;
276                 mov     r0, r4
277 
278                 ldmfd   sp!, {r4-r9}
279                 bx      lr
280 }
281 
282 /*---------------------------------------------------------------------------*
283   Name: MI_ReadUncompLZ8
284 
285   Description: Performs streaming decompression of LZ-compressed data.
286                 Data is written in units of 8 bits. Data cannot be directly uncompressed to VRAM.
287 
288   Arguments: context Pointer to the LZ uncompressed context
289                 data    Pointer to the next data
290                 len     Data size
291 
292   Returns: Size of remaining uncompressed data.
293 
294  *---------------------------------------------------------------------------*/
MI_ReadUncompLZ8(register MIUncompContextLZ * context,register const u8 * data,register u32 len)295 asm s32 MI_ReadUncompLZ8( register MIUncompContextLZ *context, register const u8* data, register u32 len )
296 {
297                 stmfd   sp!, {r4-r11}
298                                                                  // r0: context, r1: data, r2: len
299                 ldr     r3,  [r0, #MIUncompContextLZ.destp]      // r3:  destp      = context->destp;
300                 ldr     r4,  [r0, #MIUncompContextLZ.destCount]  // r4:  destCount  = context->destCount;
301                 ldrb    r5,  [r0, #MIUncompContextLZ.flags]      // r5:  flags      = context->flags;
302                 ldrb    r6,  [r0, #MIUncompContextLZ.flagIndex]  // r6:  flagIndex  = context->flagIndex;
303                 ldr     r7,  [r0, #MIUncompContextLZ.length]     // r7:  length     = context->length
304                 ldrb    r8,  [r0, #MIUncompContextLZ.lengthFlg]  // r8:  lengthFlg  = context->lengthFlg;
305                 ldrb    r11, [r0, #MIUncompContextLZ.exFormat]   // r11: exFormat   = context->exFormat;
306 @21:
307                 cmp     r4, #0                  //  while (destCount > 0) {
308                 ble     @29
309 
310                 cmp     r6, #0                  //      wihle ( flagIndex > 0 ) {
311                 beq     @28
312 @22
313                 cmp     r2, #0                  //          if ( len == 0 ) { return destCount }
314                 beq     @29
315 
316                 tst     r5, #0x80               //          if ( ! flags & 0x80 ) {
317                 bne     @23
318                 ldrb    r9, [r1], #1            //              *destp++ = *srcp++;
319                 sub     r4, r4, #1              //              destCount--;    // <- avoid pipe stall
320                 sub     r2, r2, #1              //              len--;
321 #ifdef MI_USE_STRB
322                 strb    r9, [r3], #1
323 #else
324                 swpb    r9, r9, [r3]
325                 add     r3, r3, #1
326 #endif
327                 b       @26
328 @23:                                            //          } else {
329                 cmp     r8, #0                  //              while ( lengthFlg > 0 ) {
330                 beq     @24                     //                  if ( exFormat ) {
331                 cmp     r11, #1
332                 bne     @23_9
333 
334                 subs    r8, r8, #1              //                      --lengthFlg;
335                 beq     @23_7                   //                      switch ( lengthFlg ) {
336                 cmp     r8, #1
337                 beq     @23_6
338                                                 //                      case 2:
339                 ldrb    r7, [r1], #1            //                          length = *data++;
340                 tst     r7, #0xE0
341                 beq     @23_4
342                                                 //                          if ( (length >> 4) > 1 ) {
343                 add     r7, r7, #0x10           //                              length += (1 << 4);
344                 mov     r8, #0                  //                              lengthFlg = 0;
345                 b       @23_10                  //                          }
346 @23_4:                                          //                          else {
347                 mov     r10, #0x110             //                              length += (0xF + 2) << 4;
348                 tst     r7, #0x10               //
349                 beq     @23_5                   //                              if ( (length >> 4) == 1 ) {
350 
351                 and     r7, r7, #0xF            //                                  length = (length & 0x0F) << 16;
352                 add     r10, r10, #0x1000       //                                  length += (0xFF + 1) << 4;
353                 add     r7, r10, r7, lsl #16
354                 b       @23_8                   //                              }
355 @23_5:                                          //                              else {
356                 and     r7, r7, #0xF            //                                  length = (length & 0xF) << 8;
357                 add     r7, r10, r7, lsl #8     //                                  lengthFlg = 1;
358                 mov     r8, #1                  //                              }
359                 b       @23_8                   //                          } break;
360 @23_6:                                          //                      case 1:
361                 ldrb    r10, [r1], #1           //                          length += (*data++) << 8;
362                 add     r7, r7, r10, lsl #8     //                          break;
363                 b       @23_8                   //
364 @23_7:                                          //                      case 0:
365                 ldrb    r10, [r1], #1           //                          length += *data++;
366                 add     r7, r7, r10             //                          break;
367                 b       @23_10
368 @23_8:                                          //                      }
369                 subs    r2, r2, #1              //                      if ( --len == 0 ) { return destCount; }
370                 beq     @29                     //                  }
371                 b       @23
372 
373 @23_9:                                          //                  else {
374                 ldrb    r7, [r1], #1            //                      length = *data++;
375                 add     r7, r7, #0x30           //                      length += (3 << 4);
376                 mov     r8, #0                  //                      lengthFlg = 0;
377 @23_10:
378                 subs    r2, r2, #1              //                      if ( --len == 0 ) { return destCount }
379                 beq     @29                     //                  }
380                                                 //              }
381 @24:
382                 and     r9, r7, #0xF            //  r9:         offset = ( length & 0xF ) << 8;
383                 mov     r10, r9, lsl #8
384                 ldrb    r9, [r1], #1            //              offset = ( offset | *data++ ) + 1;
385                 mov     r8, #3                  //              lengthFlg = 3;  // <- avoid pipe stall
386                 sub     r2, r2, #1              //              len--;
387                 orr     r9, r9, r10
388                 add     r9, r9, #1
389                 movs    r7, r7, asr #4          //              length = length >> 4;
390                 beq     @26                     //              while ( length > 0 ) {
391 @25:
392                 ldrb    r10, [r3, -r9]          //                  *destp++ = *(destp - offset);
393                 sub     r4, r4, #1              //                  destCount--;    // <- avoid pipe stall
394 #ifdef MI_USE_STRB
395                 strb    r10, [r3], #1
396 #else
397                 swpb    r10, r10, [r3]
398                 add     r3, r3, #1
399 #endif
400                 subs    r7, r7, #1              //                  length--;
401                 bgt     @25                     //              }
402 @26:                                            //          }
403                 cmp     r4, #0                  //          if ( destCount == 0 ) { return destCount }
404                 beq     @29
405                 mov     r5, r5, lsl #1          //          flags <<= 1;
406                 subs    r6, r6, #1              //          flagIndex--;
407                 bne     @22                     //      }
408 
409 @28:
410                 cmp     r2, #0                  //      if ( len == 0 ) { return destCount }
411                 beq     @29
412                 ldrb    r5, [r1], #1            //      flags = *data++;
413                 mov     r6, #8                  //      flagIndex = 8;
414                 sub     r2, r2, #1              //      len--
415                 b       @21                     //  }
416 
417 @29:
418                 str     r3,  [r0, #MIUncompContextLZ.destp]      // context->destp       = destp;
419                 str     r4,  [r0, #MIUncompContextLZ.destCount]  // context->destCount   = destCount;
420                 strb    r5,  [r0, #MIUncompContextLZ.flags]      // context->flags      = flags;
421                 strb    r6,  [r0, #MIUncompContextLZ.flagIndex]  // context->flagIndex  = flagIndex;
422                 str     r7,  [r0, #MIUncompContextLZ.length]     // context->length     = length;
423                 strb    r8,  [r0, #MIUncompContextLZ.lengthFlg]  // context->lengthFlg  = lengthFlg;
424                 strb    r11, [r0, #MIUncompContextLZ.exFormat]   // context->exFormat   = exFormat
425                 mov     r0, r4                  // return destCount
426 
427                 ldmfd   sp!, {r4-r11}
428                 bx      lr
429 }
430 
431 
432 /*---------------------------------------------------------------------------*
433   Name: MI_ReadUncompLZ16
434 
435   Description: Performs streaming uncompression of LZ compressed data.
436                 Data is written in 16-bit units. Data can be directly uncompressed to VRAM, as well, but this is slower than MI_ReadUncompLZ8.
437 
438 
439   Arguments: context Pointer to the LZ uncompressed context
440                 data    Pointer to the next data
441                 len     Data size
442 
443   Returns: Size of remaining uncompressed data.
444 
445  *---------------------------------------------------------------------------*/
MI_ReadUncompLZ16(register MIUncompContextLZ * context,register const u8 * data,register u32 len)446 asm s32 MI_ReadUncompLZ16( register MIUncompContextLZ *context, register const u8* data, register u32 len )
447 {
448                 stmfd   sp!, {r4-r12,lr}
449                                                                  // r0: context, r1: data, r2: len
450                 ldr     r3,  [r0, #MIUncompContextLZ.destp]      // r3:  destp      = context->destp;
451                 ldr     r4,  [r0, #MIUncompContextLZ.destCount]  // r4:  destCount  = context->destCount;
452                 ldrb    r5,  [r0, #MIUncompContextLZ.flags]      // r5:  flags      = context->flags;
453                 ldrb    r6,  [r0, #MIUncompContextLZ.flagIndex]  // r6:  flagIndex  = context->flagIndex;
454                 ldr     r7,  [r0, #MIUncompContextLZ.length]     // r7:  length     = context->length
455                 ldrb    r8,  [r0, #MIUncompContextLZ.lengthFlg]  // r8:  lengthFlg  = context->lengthFlg;
456                 ldrh    r9,  [r0, #MIUncompContextLZ.destTmp]    // r9:  destTmp    = context->destTmp;
457                 ldrb    r10, [r0, #MIUncompContextLZ.destTmpCnt] // r10: destTmpCnt = context->destTmpCnt;
458                 ldrb    r14, [r0, #MIUncompContextLZ.exFormat]   // r14: exFormat   = context->exFormat;
459 
460                 stmfd   sp!, {r0}
461 
462 @21:
463                 cmp     r4, #0                  //  while (destCount > 0) {
464                 ble     @29
465 
466                 cmp     r6, #0                  //      wihle ( flagIndex > 0 ) {
467                 beq     @28
468 @22
469                 cmp     r2, #0                  //          if ( len == 0 ) { return destCount }
470                 beq     @29
471 
472                 tst     r5, #0x80               //          if ( ! flags & 0x80 ) {
473                 bne     @23
474                 ldrb    r11, [r1], #1           //              destTmp |= (*data++) << destTmpCnt;
475                 sub     r2, r2, #1              //              len--;  // <- avoid pipe stall
476                 orr     r9, r9, r11, lsl r10
477                 add     r10, r10, #8            //              destTmpCnt += 8;
478                 cmp     r10, #16                //              if ( destTmpCnt == 16 ) {
479                 bne     @26
480                 strh    r9, [r3], #2            //                  *(u16*)destp = destTmp; destp += 2;
481                 sub     r4, r4, #2              //                  destCount -= 2;
482                 mov     r9, #0                  //                  destTmp = 0;
483                 mov     r10, #0                 //                  destTmpCount = 0;
484                                                 //              }
485                 b       @26
486 @23:                                            //          } else {
487                 cmp     r8, #0                  //              while ( lengthFlg > 0 ) {
488                 beq     @24                     //                  if ( exFormat ) {
489                 cmp     r14, #1
490                 bne     @23_9
491 
492                 subs    r8, r8, #1              //                      --lengthFlg;
493                 beq     @23_7                   //                      switch ( lengthFlg ) {
494                 cmp     r8, #1
495                 beq     @23_6
496                                                 //                      case 2:
497                 ldrb    r7, [r1], #1            //                          length = *data++;
498                 tst     r7, #0xE0
499                 beq     @23_4
500                                                 //                          if ( (length >> 4) > 1 ) {
501                 add     r7, r7, #0x10           //                              length += (1 << 4);
502                 mov     r8, #0                  //                              lengthFlg = 0;
503                 b       @23_10                  //                          }
504 @23_4:                                          //                          else {
505                 mov     r11, #0x110             //                              length += (0xF + 2) << 4;
506                 tst     r7, #0x10               //
507                 beq     @23_5                   //                              if ( (length >> 4) == 1 ) {
508 
509                 and     r7, r7, #0xF            //                                  length = (length & 0x0F) << 16;
510                 add     r11, r11, #0x1000       //                                  length += (0xFF + 1) << 4;
511                 add     r7, r11, r7, lsl #16
512                 b       @23_8                   //                              }
513 @23_5:                                          //                              else {
514                 and     r7, r7, #0xF            //                                  length = (length & 0xF) << 8;
515                 add     r7, r11, r7, lsl #8     //                                  lengthFlg = 1;
516                 mov     r8, #1                  //                              }
517                 b       @23_8                   //                          } break;
518 @23_6:                                          //                      case 1:
519                 ldrb    r11, [r1], #1           //                          length += (*data++) << 8;
520                 add     r7, r7, r11, lsl #8     //                          break;
521                 b       @23_8                   //
522 @23_7:                                          //                      case 0:
523                 ldrb    r11, [r1], #1           //                          length += *data++;
524                 add     r7, r7, r11             //                          break;
525                 b       @23_10
526 @23_8:                                          //                      }
527                 subs    r2, r2, #1              //                      if ( --len == 0 ) { return destCount; }
528                 beq     @29                     //                  }
529                 b       @23
530 
531 @23_9:                                          //                  else {
532                 ldrb    r7, [r1], #1            //                      length = *data++;
533                 add     r7, r7, #0x30           //                      length += (3 << 4);
534                 mov     r8, #0                  //                      lengthFlg = 0;
535 @23_10:
536                 subs    r2, r2, #1              //                      if ( --len == 0 ) { return destCount }
537                 beq     @29                     //                  }
538                                                 //              }
539 @24:
540                 and     r11, r7, #0xF           //  r11:        offset = ( length & 0xF ) << 8;
541                 mov     r12, r11, lsl #8
542                 ldrb    r11, [r1], #1           //              offset = ( offset | *data++ ) + 1;
543                 mov     r8, #3                  //              lengthFlg = 3;  // <- avoid pipe stall
544                 sub     r2, r2, #1              //              len--
545                 orr     r11, r11, r12
546                 add     r11, r11, #1
547                 movs    r7, r7, asr #4          //              length = length >> 4;
548                 beq     @26                     //              while ( length > 0 ) {
549 @25:
550                 subs    r12, r11, r10, lsr #3   //  r12:            offsetTmp = offset - ( destTmpCnt / 8 );
551                 bne     @25_1                   //                  if ( offsetTmp == 0 ) {
552                 and     r0, r9, #0xF            //                      destTmp |= ( destTmp & 0xF ) << 8;
553                 orr     r9, r9, r0, lsl #8
554                 b       @25_2
555 @25_1:                                          //                  } else {
556                 add     r0, r12, #1             //  r0:                 tmpData = *(u16*)( destp - ( (offsetTmp + 1) & ~0x1 ) )
557                 mov     r0, r0, lsr #1
558                 sub     r0, r3, r0, lsl #1
559                 ldrh    r0, [r0, #0]
560                 tst     r12, #1                 //                      if ( offsetTmp & 1 ) {
561                 movne   r0, r0, lsr #8          //                          tmpData >>= 8;
562                                                 //                      } else {
563                 andeq   r0, r0, #0xFF           //                          tmpData &= 0xFF;
564                                                 //                      }
565                 orr     r9, r9, r0, lsl r10     //                       destTmp |= tmpData << destTmpCnt;
566 @25_2:                                          //                  }
567                 add     r10, r10, #8            //                  destTmpCnt += 8;
568                 cmp     r10, #16                //                  if ( destTmpCnt == 16 ) {
569                 bne     @25_3
570                 strh    r9, [r3], #2            //                      *(u16*)destp = destTmp; destp += 2;
571                 sub     r4, r4, #2              //                      destCount -= 2;
572                 mov     r9, #0                  //                      destTmp = 0;
573                 mov     r10, #0                 //                      destTmpCnt = 0;
574                                                 //                  }
575 @25_3:
576                 subs    r7, r7, #1              //                  length--;
577                 bgt     @25                     //              }
578 @26:                                            //          }
579                 cmp     r4, #0                  //          if ( destCount == 0 ) { return destCount }
580                 beq     @29
581                 mov     r5, r5, lsl #1          //          flags <<= 1;
582                 subs    r6, r6, #1              //          flagIndex--;
583                 bne     @22                     //      }
584 
585 @28:
586                 cmp     r2, #0                  //      if ( len == 0 ) { return destCount }
587                 beq     @29
588                 ldrb    r5, [r1], #1            //      flags = *data++;
589                 mov     r6, #8                  //      flagIndex = 8;
590                 sub     r2, r2, #1              //      len--
591                 b       @21                     //  }
592 
593 @29:
594                 ldmfd   sp!, {r0}
595                 str     r3,  [r0, #MIUncompContextLZ.destp]      // context->destp       = destp;
596                 str     r4,  [r0, #MIUncompContextLZ.destCount]  // context->destCount   = destCount;
597                 strb    r5,  [r0, #MIUncompContextLZ.flags]      // context->flags      = flags;
598                 strb    r6,  [r0, #MIUncompContextLZ.flagIndex]  // context->flagIndex  = flagIndex;
599                 str     r7,  [r0, #MIUncompContextLZ.length]     // context->length     = length;
600                 strb    r8,  [r0, #MIUncompContextLZ.lengthFlg]  // context->lengthFlg  = lengthFlg;
601                 strh    r9,  [r0, #MIUncompContextLZ.destTmp]    // context->destTmp     = destTmp;
602                 strb    r10, [r0, #MIUncompContextLZ.destTmpCnt] // context->destTmpCnt = destTmpCnt;
603                 strb    r14, [r0, #MIUncompContextLZ.exFormat]   // context->exFormat   = exFormat;
604                 mov     r0, r4                  // return destCount
605 
606                 ldmfd   sp!, {r4-r12,lr}
607                 bx      lr
608 }
609 
610 
611 /*---------------------------------------------------------------------------*
612   Name: MI_ReadUncompHuffman
613 
614   Description: Performs streaming decompression of Huffman-compressed data.
615 
616   Arguments: context Pointer to the Huffman uncompressed context
617                 data    Pointer to the next data
618                 len     Data size
619 
620   Returns: Size of remaining uncompressed data.
621 
622  *---------------------------------------------------------------------------*/
623 #define TREE_END_MASK   0x80
624 
MI_ReadUncompHuffman(register MIUncompContextHuffman * context,register const u8 * data,register u32 len)625 asm s32 MI_ReadUncompHuffman( register MIUncompContextHuffman *context, register const u8* data, register u32 len )
626 {
627                 stmfd   sp!, {r4-r12, lr}
628                                                                       // r0: context, r1: data, r2: len
629                 ldr     r3, [r0, #MIUncompContextHuffman.destp]       // r3: destp      = context->destp;
630                 ldr     r4, [r0, #MIUncompContextHuffman.destCount]   // r4: destCount  = context->destCount;
631                 ldr     r5, [r0, #MIUncompContextHuffman.treep]       // r5: treep      = context->treep;
632                 ldr     r6, [r0, #MIUncompContextHuffman.srcTmp]      // r6: srcTmp     = context->srcTmp;
633                 ldr     r7, [r0, #MIUncompContextHuffman.destTmp]     // r7: destTmp    = context->destTmp;
634                 ldrsh   r8, [r0, #MIUncompContextHuffman.treeSize]    // r8: treeSize   = context->treeSize;
635                 ldrb    r9, [r0, #MIUncompContextHuffman.srcTmpCnt]   // r9: srcTmpCnt  = context->srcTmpCnt;
636                 ldrb    r10, [r0, #MIUncompContextHuffman.destTmpCnt] // r10: destTmpCnt = context->destTmpCnt;
637                 ldrb    r11, [r0, #MIUncompContextHuffman.bitSize]    // r11: bitSize   = context->bitSize;
638 
639                 cmp     r8, #0                                  //  if ( treeSize < 0 ) {
640                 beq     @12
641                 bgt     @11
642                 ldrb    r8, [r1], #1                            //      treeSize = ( *data + 1 ) * 2 - 1;
643                 sub     r2, r2, #1                              //      len--;  // <- avoid pipe stall
644                 strb    r8, [r5], #1                            //      *treep++ = *data++;
645                 add     r8, r8, #1
646                 mov     r8, r8, lsl #1
647                 sub     r8, r8, #1
648 @11:                                                            //  }
649                                                                 //  while ( treeSize > 0 ) {
650                 cmp     r2, #0                                  //      if ( len == 0 ) { return destCount; }
651                 beq     @19
652                 ldrb    r12, [r1], #1                           //      *treep++ = *data++;
653                 sub     r2, r2, #1                              //      len--;  // <- avoid pipe stall
654                 strb    r12, [r5], #1
655                 subs    r8, r8, #1                              //      treeSize--;
656                 addeq   r5, r0, #MIUncompContextHuffman.tree[1] //      if ( treeSize == 0 ) { treep = &context->tree[ 1 ]; }
657                 bgt     @11                                     //  }
658 @12:
659                 cmp     r4, #0                                  //  while (destCount > 0) {
660                 ble     @19
661 @13:
662                 cmp     r9, #32                                 //      while ( srcTmpCnt < 32 ) {
663                 bge     @15
664 @14:
665                 cmp     r2, #0                                  //          if ( len == 0 ) { return destCount; }
666                 beq     @19
667                 ldr     r12, [r1], #1                           //          srcTmp |= (*data++) << srcTmpCnt;
668                 sub     r2, r2, #1                              //          len--;  // <- avoid pipe stall
669                 orr     r6, r6, r12, lsl r9
670                 add     r9, r9, #8                              //          srcTmpCnt += 8;
671                 cmp     r9, #32                                 //      }
672                 blt     @14
673 @15:                                                            //      do {
674                 mov     r12, r6, lsr #31                        // r12:     select = srcTmp >> 31;
675                 ldrb    r14, [r5, #0]                           // r14:     endFlag = ( *treep << select ) & TREE_END_MASK;
676                 mov     r5, r5, lsr #1                          //          treep = ( treep & ~0x1 ) + ( ( (*treep & 0x3F) + 1 ) * 2 ) + select;
677                 mov     r5, r5, lsl #1
678                 and     r8, r14, #0x3F
679                 add     r8, r8, #1
680                 add     r5, r5, r8, lsl #1
681                 add     r5, r5, r12
682                 mov     r8, #0
683                 mov     r14, r14, lsl r12
684                 ands    r14, r14, #TREE_END_MASK
685                 mov     r6, r6, lsl #1                          //          srcTmp <<= 1;
686                 sub     r9, r9, #1                              //          srcTmpCnt--;
687                 beq     @17                                     //          if ( ! endFlag ) { continue; }
688 
689                 mov     r7, r7, lsr r11                         //          destTmp >>= bitSize;
690                 ldrb    r12, [r5, #0]                           //          destTmp |= *treep << ( 32 - bitSize );
691                 rsb     r14, r11, #32
692                 orr     r7, r7, r12, lsl r14
693                 add     r5, r0, #MIUncompContextHuffman.tree[1] //          treep = &context->tree[ 1 ];
694                 add     r10, r10, r11                           //          destTmpCnt += bitSize;
695 
696                 cmp     r4, r10, asr #3                         //          if ( destCount <= destTmpCnt / 8 ) {
697                 bgt     @16
698                 rsb     r12, r10, #32                           //              destTmp >>= 32 - destTmpCnt;
699                 mov     r7, r7, asr r12
700                 mov     r10, #32                                //              destTmpCnt = 32;
701 @16:                                                            //          }
702                 cmp     r10, #32                                //          if ( destTmpCnt == 32 ) {
703                 bne     @17
704                 str     r7, [r3], #4                            //              *(u32*)destp = destTmp; destp += 4;
705                 mov     r10, #0                                 //              destTmpCnt = 0;
706                 subs    r4, r4, #4                              //              destCount -= 4;
707                 movle   r4, #0                                  //              if ( destCount <= 0 ) { return 0 };
708                 ble     @19
709                                                                 //          }
710 @17:
711                 cmp     r9, #0                                  //      } while ( srcTmpCnt > 0 );
712                 bgt     @15
713                 cmp     r4, #0                                  //  }
714                 bgt     @13
715 
716 @19:
717                 str     r3, [r0, #MIUncompContextHuffman.destp]       // r3: context->destp       = destp;
718                 str     r4, [r0, #MIUncompContextHuffman.destCount]   // r4: context->destCount   = destCount;
719                 str     r5, [r0, #MIUncompContextHuffman.treep]       // r5: context->treep       = treep;
720                 str     r6, [r0, #MIUncompContextHuffman.srcTmp]      // r6: context->srcTmp      = srcTmp;
721                 str     r7, [r0, #MIUncompContextHuffman.destTmp]     // r7: context->destTmp     = destTmp;
722                 strh    r8, [r0, #MIUncompContextHuffman.treeSize]    // r8: context->treeSize    = treeSize;
723                 strb    r9, [r0, #MIUncompContextHuffman.srcTmpCnt]   // r9: context->srcTmpCnt   = srcTmpCnt;
724                 strb    r10, [r0, #MIUncompContextHuffman.destTmpCnt] // r10: context->destTmpCnt = destTmpCnt;
725                 strb    r11, [r0, #MIUncompContextHuffman.bitSize]    // r11: context->bitSize    = bitSize;
726                 mov     r0, r4                                  //  return destCount
727 
728                 ldmfd   sp!, {r4-r12, lr}
729                 bx      lr
730 
731 }
732 
733 //---- End limitation of processor mode
734 #include <nitro/codereset.h>
735