// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\euser\epoc\arm\uc_huffman.cia
//
//
#include "e32huffman.h"
#include <cpudefs.h>
#ifdef __HUFFMAN_MACHINE_CODED__
// NB The EABI layout of TBitInput is different from GCC. Its vtbl is at
// offset 0 rather than offset 16
EXPORT_C __NAKED__ TUint TBitInput::ReadL()
/** Read a single bit from the input
Return the next bit in the input stream. This will call UnderflowL() if
there are no more bits available.
@return The next bit in the stream
@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
to get more data
*/
{
asm(".code 32");
#ifdef __EABI__
asm("ldmib r0!, {r2,r3}");
#else
asm("ldmia r0!, {r2,r3}");
#endif
// r0 = this+8
asm("subs r2, r2, #1");
asm("movpl r12, r3, asl #1");
#ifdef __EABI__
asm("stmplda r0, {r2,r12}");
#else
asm("stmpldb r0, {r2,r12}");
#endif
asm("movpl r0, r3, lsr #31");
__JUMP(pl,lr);
asm("mov r12, #0");
asm("b __readmorebits"); // r2==-1, r12==0 -> so all set
}
EXPORT_C __NAKED__ TUint TBitInput::ReadL(TInt aSize)
/** Read a multi-bit value from the input
Return the next few bits as an unsigned integer. The last bit read is
the least significant bit of the returned value, and the value is
zero extended to return a 32-bit result.
A read of zero bits will always reaturn zero.
This will call UnderflowL() if there are not enough bits available.
@param "TInt aSize" The number of bits to read
@return The bits read from the stream
@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
to get more data
*/
{
asm(".code 32");
#ifdef __EABI__
asm(" ldmib r0!, {r2,r3}");
#else
asm(" ldmia r0!, {r2,r3}");
#endif
asm(" subs r2, r2, r1");
asm(" movpl r12, r3, asl r1");
#ifdef __EABI__
asm(" stmplda r0, {r2,r12}");
#else
asm(" stmpldb r0, {r2,r12}");
#endif
asm(" rsb r1, r1, #32");
asm(" movpl r0, r3, lsr r1");
__JUMP(pl,lr);
// r0=this+8, r1=32-#reqd, r2=count-#reqd (<0), r3=bits
asm(" sub r1, r1, r2"); // r1 = 32-iCount
asm(" mov r3, r3, lsr r1"); // scrub existing bits
asm(" rsb r1, r2, #0"); // r1 = #reqd-iCount
asm(" mov r12, r3, lsl r1"); // r12 has bits in final position
asm("__readmorebits:");
//r0=this+8
asm(" stmfd sp!, {r12,lr}");
#ifdef __EABI__
asm(" ldmib r0!, {r1,r14}"); // r1=remain, r14=ptr
#else
asm(" ldmia r0!, {r1,r14}"); // r1=remain, r14=ptr
#endif
//r0=this+16
asm(" cmp r1, #0");
asm(" ble __readunderflow");
asm(" ldr r12, [r14], #4");
asm(" subs r3, r1, #32");
#ifdef __EABI__
asm(" stmda r0!, {r3,r14}");
#else
asm(" stmdb r0!, {r3,r14}");
#endif
// r0=this+8
asm(" addmi r1, r2, r1");
asm(" addpl r1, r2, #32"); // r1 = bits left in
asm(" eor r3, r12, r12, ror #16");
asm(" bic r3, r3, #16711680");
asm(" mov r3, r3, lsr #8");
asm(" eor r3, r3, r12, ror #8"); // r3=bits
// r0=this+8, r1=count-#reqd, r2=-#reqd, r3=bits, sp[0]=accum, sp[4]=return-pc
asm(" cmp r1, #0");
asm(" bmi __readgoroundagain");
asm("__readhavebits:");
asm(" rsb r12, r2, #0");
asm(" mov r12, r3, asl r12");
#ifdef __EABI__
asm(" stmda r0, {r1,r12}");
#else
asm(" stmdb r0, {r1,r12}");
#endif
asm(" ldmfd sp!, {r12,lr}");
asm(" add r2, r2, #32");
asm(" orr r0, r12, r3, lsr r2");
__JUMP(,lr);
asm("__readunderflow:");
#ifdef __EABI__
asm(" ldr r3, [r0, #-16]!"); // restore r0 to this
#else
asm(" ldr r3, [r0], #-16"); // restore r0 to this
#endif
asm(" stmfd sp!, {r0,r2}");
// at this point the stack has grown by 16 bytes from the CFA
__EH_FRAME_ADDRESS(sp,16)
// The stack looks like this
// CFA-4 -> lr
// CFA-8 -> r12
// CFA-12 -> r2
// CFA-16 -> r0
// So we need to record lr @ CFA-4
// Nothing else needs to be restored since there's no barrier here
__EH_FRAME_SAVE1(lr,-4)
asm(" adr lr, 1f ");
#ifdef __EABI__
asm(" ldr ip, [r3, #0]");
#else
asm(" ldr ip, [r3, #8]");
#endif
__JUMP(,ip);
asm("1: ");
asm(" ldmfd sp!, {r0,r2}");
#ifdef __EABI__
asm(" ldmib r0!, {r1,r3}"); // r1=count, r3=bits
#else
asm(" ldmia r0!, {r1,r3}"); // r1=count, r3=bits
#endif
asm(" adds r1, r1, r2"); // adjust count for bits to extract
asm(" bpl __readhavebits");
asm("__readgoroundagain:");
// r0=this+8, r1=count-#reqd (<0), r2=-#reqd, r3=bits, sp[0]=accum, sp[4]=return-pc
asm(" sub r12, r1, r2"); // r12 = iCount
asm(" rsb r12, r12, #32"); // r12= 32-iCount
asm(" mov r3, r3, lsr r12"); // scrub existing bits
asm(" ldmfd sp!, {r12,lr}");
asm(" mov r2, r1"); // r2 = iCount-#reqd
asm(" rsb r1, r1, #0"); // r1 = #reqd-iCount
asm(" orr r12, r12, r3, lsl r1"); // r12 has bits in final position
asm(" b __readmorebits");
}
EXPORT_C __NAKED__ TUint TBitInput::HuffmanL(const TUint32* aTree)
/** Read and decode a Huffman Code
Interpret the next bits in the input as a Huffman code in the specified
decoding. The decoding tree should be the output from Huffman::Decoding().
@param "const TUint32* aTree" The huffman decoding tree
@return The symbol that was decoded
@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
to get more data
*/
{
asm(".code 32");
asm("__huffman:");
#ifdef __EABI__
asm(" ldmib r0!, {r2,r3}");
#else
asm(" ldmia r0!, {r2,r3}");
#endif
asm("__decode:");
asm(" ldr r12, [r1]");
asm(" subs r2, r2, #4");
asm(" bmi __fewbits");
asm("__fastloop:");
asm(" movs r3, r3, asl #1");
asm(" movcc r12, r12, asl #16");
asm(" tst r12, #65536");
asm(" bne __fastdecoded");
asm(" ldr r12, [r1, r12, lsr #16]!");
asm(" sub r2, r2, #1");
asm(" movs r3, r3, asl #1");
asm(" movcc r12, r12, asl #16");
asm(" tst r12, #65536");
asm(" bne __fastdecoded");
asm(" ldr r12, [r1, r12, lsr #16]!");
asm(" sub r2, r2, #1");
asm(" movs r3, r3, asl #1");
asm(" movcc r12, r12, asl #16");
asm(" tst r12, #65536");
asm(" bne __fastdecoded");
asm(" ldr r12, [r1, r12, lsr #16]!");
asm(" sub r2, r2, #1");
asm(" movs r3, r3, asl #1");
asm(" movcc r12, r12, asl #16");
asm(" tst r12, #65536");
asm(" bne __fastdecoded");
asm(" ldr r12, [r1, r12, lsr #16]!");
asm(" subs r2, r2, #1");
asm(" bpl __fastloop");
asm("__fewbits:");
asm(" adds r2, r2, #3");
asm(" bmi __nobits");
asm("__slowloop:");
asm(" movs r3, r3, asl #1");
asm(" movcc r12, r12, asl #16");
asm(" tst r12, #65536");
asm(" bne __decoded");
asm(" ldr r12, [r1, r12, lsr #16]!");
asm(" subs r2, r2, #1");
asm(" bpl __slowloop");
asm("__nobits:");
// r0=this, r1=tree, r2=count (-1), r3=bits (0), r12=node=*tree
// must preserve r0,r1
#ifdef __EABI__
asm(" ldmib r0!, {r2,r3}"); // r2=remain, r3=ptr
#else
asm(" ldmia r0!, {r2,r3}"); // r2=remain, r3=ptr
#endif
asm(" cmp r2, #0");
asm(" ble __underflow");
asm(" ldr r12, [r3], #4");
asm(" subs r2, r2, #32");
#ifdef __EABI__
asm(" stmda r0!, {r2,r3}");
#else
asm(" stmdb r0!, {r2,r3}");
#endif
asm(" addmi r2, r2, #32");
asm(" movpl r2, #32");
asm(" eor r3, r12, r12, ror #16");
asm(" bic r3, r3, #16711680");
asm(" mov r3, r3, lsr #8");
asm(" eor r3, r3, r12, ror #8");
asm(" b __decode");
asm("__underflow:");
#ifdef __EABI__
asm(" ldr r3, [r0, #-16]!"); // restore r0 to this
#else
asm(" ldr r3, [r0], #-16"); // restore r0 to this
#endif
asm(" stmfd sp!, {r0,r1,r2,lr}");
// sp is 16 bytes from CFA
__EH_FRAME_ADDRESS(sp,16)
// The stack looks like this:
// CFA-4 -> lr
// CFA-8 -> r2
// CFA-12 -> r1
// CFA-16 -> r0
// We saved lr @ CFA-4
// Nothing else needs to be restored since there's no barrier here
__EH_FRAME_SAVE1(lr,-4)
asm(" adr lr, 1f ");
#ifdef __EABI__
asm(" ldr ip, [r3, #0]");
#else
asm(" ldr ip, [r3, #8]");
#endif
__JUMP(,ip);
asm("1: ");
asm(" ldmfd sp!, {r0,r1,r2,lr}");
asm(" b __huffman");
asm("__fastdecoded:");
asm(" add r2, r2, #3");
asm("__decoded:");
#ifdef __EABI__
asm(" stmda r0, {r2, r3}");
#else
asm(" stmdb r0, {r2, r3}");
#endif
asm(" mov r0, r12, lsr #17");
__JUMP(,lr);
}
#endif