#include <stdlib.h>
#include <math.h>
#include "ucps2.h"


void RMBitSelLDPC(int ConfigBaseAddr,int EkLength,int NullPos,int NullLen,int k0,int EncodedCBSizes,int InputAddr,int TempAddr2,int TempAddr,int OutputAddr)
{
	int i,N,Temp;
	int Loop,ModValue;
	int NullEndPos,TempE,TempEPos,NewNullPos,Newk0,k0mod8;
	int Seg1Len,Seg2Len;
	int LoadTime0,LoadTime1,LoadTime2,LoadTime3,LoadTime4,StoreTime;
	volatile int *AddrPara = (volatile int *)ConfigBaseAddr;


	N = EncodedCBSizes;
	NullEndPos = NullPos+NullLen;
	k0mod8 = k0&7;
	TempE = EkLength+NullLen+k0mod8;


	if((N-NullLen)>EkLength)//shorten
	{

		if((k0+TempE)>N)  //2 segments
		{
			//Step1: bit to byte
			Seg1Len = N-(k0-k0mod8);
			Seg2Len = TempE-Seg1Len;
			AddrPara[0*16] = (Seg1Len>>6)+((Seg1Len&63)!=0);
			AddrPara[1*16] = InputAddr+(k0>>3);
			AddrPara[2*16] = TempAddr2;
			AddrPara[0*16+1] = (Seg2Len>>6)+((Seg2Len&63)!=0);
			AddrPara[3*16] = (InputAddr);
			AddrPara[3*16+4] = 0x8;
			AddrPara[4*16] = TempAddr2+Seg1Len;
			if(((NullPos>Seg2Len)&&(NullEndPos<=k0))||(NullLen == 0))
			{
				//Step2:remove Null bit check
				AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
				AddrPara[5*16] = (TempAddr2)+k0mod8;
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = 0;
			}
			else if((Seg2Len<NullPos)&&(NullPos<=k0))
			{
				//Step2:remove Null bit check
				AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
				AddrPara[5*16] = (TempAddr2)+NullEndPos-(k0-k0mod8);
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = 0;
			}
			else if((NullPos>k0)||(NullEndPos<=Seg2Len))
			{
				if(NullPos>k0)
				{
					NewNullPos = NullPos-(k0-k0mod8);
				}
				else
				{
					NewNullPos = Seg1Len + NullPos;  //check
				}
				Seg1Len = NewNullPos-k0mod8;
				Seg2Len	= EkLength-Seg1Len;
				//Step2:remove Null bit
				AddrPara[0*16+2] = ((Seg1Len) >> 6) + (((Seg1Len) & 63)!=0);
				AddrPara[5*16] = TempAddr2+(k0mod8);
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = ((Seg2Len) >> 6) + (((Seg2Len) & 63)!=0);
				AddrPara[7*16] = TempAddr2+ NewNullPos+NullLen;
				AddrPara[8*16] = OutputAddr+ Seg1Len;
			}
			else if((NullEndPos>Seg2Len)&&(NullPos<=Seg2Len))
			{
					//Step2:remove Null bit check
					NewNullPos = Seg1Len + NullPos;;
					AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
					AddrPara[5*16] = TempAddr2+k0mod8;
					AddrPara[6*16] = OutputAddr;
					AddrPara[0*16+3] = 0;
			}
		}
	    else
		{
	    	//Step1: bit to byte
	    	//Seg1Len =TempE;
	    	AddrPara[0*16] = ((TempE)>>6)+((TempE&63)!=0);
	    	AddrPara[1*16] = (InputAddr)+(k0>>3);
	    	AddrPara[2*16] = TempAddr2;
	    	AddrPara[0*16+1] = 0;
	    	TempEPos = k0+TempE;
	    	if((k0>=NullEndPos)||(NullPos>=TempEPos)||(NullLen==0))
	    	{
	    		//Step2:remove Null bit check
				AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
				AddrPara[5*16] = (TempAddr2)+k0mod8;
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = 0;
	    	}
			else if((NullPos<=k0)&&(NullEndPos>=k0))
			{
				//Step2:remove Null bit check
				AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
				AddrPara[5*16] = (TempAddr2)+NullEndPos-(k0-k0mod8);
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = 0;
			}
			else if((NullPos<=TempEPos)&&(NullEndPos>=TempEPos))
			{
				//Step2:remove Null bit check
				AddrPara[0*16+2] = ((EkLength) >> 6) + ((EkLength&63)!=0);
				AddrPara[5*16] = (TempAddr2)+k0mod8;
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = 0;
			}
			else if((NullPos>k0)&&(NullEndPos<=TempEPos))
			{
				//check
				NewNullPos = NullPos-(k0-k0mod8);
				Seg1Len = NewNullPos-k0mod8;
				Seg2Len	= EkLength-Seg1Len;
				//Step2:remove Null bit
				AddrPara[0*16+2] = ((Seg1Len) >> 6) + (((Seg1Len) & 63)!=0);
				AddrPara[5*16] = TempAddr2+(k0mod8);
				AddrPara[6*16] = OutputAddr;
				AddrPara[0*16+3] = ((Seg2Len) >> 6) + (((Seg2Len) & 63)!=0);
				AddrPara[7*16] = TempAddr2+ NewNullPos+NullLen;
				AddrPara[8*16] = OutputAddr+ Seg1Len;
			}
	    	AddrPara[0*16+8] = 0;
			ModValue = 0;
		}
	}
	else //repeat
	{
		AddrPara[0*16+8] = 1;
		//Step1: bit to byte
		AddrPara[0*16] = (N>>6)+((N&63)!=0);		//ceil(N/64.0);
		AddrPara[1*16] = InputAddr;
		AddrPara[2*16] = TempAddr;


		//Step2:remove Null bit
		if(NullLen!=0)
		{
			AddrPara[0*16+1] = (NullPos>>6)+((NullPos & 63)!=0);
			AddrPara[3*16] = TempAddr;
			AddrPara[4*16] = TempAddr2;
			AddrPara[0*16+2] = ((N-NullEndPos) >> 6) + (((N-NullEndPos) & 63)!=0);
			AddrPara[5*16] = TempAddr + NullEndPos;
			AddrPara[6*16] = TempAddr2 + NullPos;

		}
		else
		{
			AddrPara[0*16+1] = (N>>6)+((N&63)!=0);
			AddrPara[3*16] = TempAddr;
			AddrPara[4*16] = TempAddr2;
			AddrPara[0*16+2] = 0;
		}

		//Step3: k0
		if(k0>=NullEndPos)
		{
			Newk0=k0-NullLen;
		}
		else if((k0<=NullPos)||(NullLen==0))
		{
			Newk0 = k0;
		}
		else
		{
			Newk0 = NullPos;
		}
		Seg1Len = (N-NullLen-Newk0);
		AddrPara[0*16+3] =  (Seg1Len >> 6) + ((Seg1Len & 63)!=0);
		AddrPara[7*16] = TempAddr2+Newk0;
		AddrPara[8*16] = OutputAddr;

		Loop = (EkLength-Seg1Len)/(N-NullLen);
		ModValue = (EkLength-Seg1Len)%(N-NullLen);
		AddrPara[0*16+4] = Loop;
		//Seg2Len = N-NullLen;
		AddrPara[0*16+5] = ((N-NullLen) >> 6) + (((N-NullLen) & 63)!=0);
		Temp  = ((N-NullLen) >> 6) + (((N-NullLen) & 63)!=0);
		AddrPara[9*16] = TempAddr2;
		AddrPara[9*16+1] = TempAddr2;
		AddrPara[9*16+2] = TempAddr2;
		AddrPara[9*16+4] = 0x40;
		AddrPara[9*16+5] = 0x0;
		AddrPara[9*16+8] = Temp |(Temp<<16);
		AddrPara[9*16+9] = Loop |(Loop<<16);


		AddrPara[10*16] = OutputAddr+Seg1Len;
		AddrPara[10*16+1] = OutputAddr+Seg1Len;
		AddrPara[10*16+2] = OutputAddr+Seg1Len;
		AddrPara[10*16+4] = 0x40;
		AddrPara[10*16+5] = N-NullLen;
		AddrPara[10*16+8] = Temp |(Temp<<16);
		AddrPara[10*16+9] = Loop |(Loop<<16);


		AddrPara[0*16+6] = (ModValue >> 6) + ((ModValue & 63)!=0);
		AddrPara[11*16] = TempAddr2;
		AddrPara[12*16] = OutputAddr+(Seg1Len)+Loop*(N-NullLen);


	}



}




void RMBitILLDPC(int ConfigBaseAddr,int EkLength,int Qm,int InputAddr,int OutputAddr)
{
	volatile int *AddrPara = (volatile int *)ConfigBaseAddr;
	int QmIdx;
	int StoreTime;
	QmIdx = (Qm>>1)-1;
	//QmIdxAddr
	AddrPara[0*16] = (MPU_ADDR(ConfigBaseAddr)) +4*0x40+0x40*4*QmIdx;
	//KI
	StoreTime = (EkLength+511)>> 9;

	AddrPara[1*16+9] = 1;
	AddrPara[1*16+10] = 1;
	AddrPara[1*16+11] = 1;

	AddrPara[2*16] = InputAddr;
	AddrPara[2*16+1] = InputAddr;
	AddrPara[2*16+2] = InputAddr;
	AddrPara[2*16+3] = InputAddr;

	if(Qm==2)
	{
		AddrPara[2*16+4] = 0x40;
		AddrPara[2*16+5] = EkLength>>1;
		AddrPara[2*16+6] = 0x40*4;
		AddrPara[2*16+8] = 4 +(4*65536);
		AddrPara[2*16+9] = 2 +(2*65536);
		AddrPara[2*16+10] = 0xffffffff;
		AddrPara[3*16] = OutputAddr;
		AddrPara[3*16+4] = 0x40;
		AddrPara[3*16+12] = EkLength>>3;
		AddrPara[1*16+9] = 0;
	}
	else if(Qm==4)
	{
		AddrPara[2*16+4] = 0x40;
		AddrPara[2*16+5] = EkLength>>1;
		AddrPara[2*16+6] = EkLength>>2;
		AddrPara[2*16+7] = 0x40*2;
		AddrPara[2*16+8] = 2 +(2*65536);
		AddrPara[2*16+9] = 2 +(2*65536);
		AddrPara[2*16+10] = 2 +(2*65536);
		AddrPara[2*16+11] = 0xffffffff;
		AddrPara[3*16] = OutputAddr;
		AddrPara[3*16+12] = EkLength>>3;
		AddrPara[3*16+4] = 0x40;
	}
	else if(Qm==6)
	{
		AddrPara[2*16+4] = 0x40;
		AddrPara[2*16+5] = EkLength/Qm*2;
		AddrPara[2*16+6] = EkLength/Qm;
		AddrPara[2*16+7] = 84;
		AddrPara[2*16+8] = 2 +(2*65536);
		AddrPara[2*16+9] = 3 +(3*65536);
		AddrPara[2*16+10] = 2 +(2*65536);
		AddrPara[2*16+11] = 0x0606ffff;
		AddrPara[3*16] = OutputAddr;
		AddrPara[3*16+4] = 0x3f;
		AddrPara[3*16+12] = EkLength>>3;
		AddrPara[3*16+13] = (63<<16)|6;
		StoreTime = (EkLength/504)+((EkLength%504)!=0);
		AddrPara[1*16+11] = 0;
	}
	else if(Qm==8)
	{
		AddrPara[2*16+4] = EkLength>>3;
		AddrPara[2*16+5] = 0x40;
		AddrPara[2*16+8] = 8 +(8*65536);
		AddrPara[2*16+9] = 0xffffffff;
		AddrPara[3*16] = OutputAddr;
		AddrPara[3*16+4] = 0x40;
		AddrPara[3*16+12] = EkLength>>3;
		AddrPara[1*16+10] = 0;
	}
	AddrPara[1*16+8] = StoreTime;
}
