/******************************************************************
 * @file  ${LDPCEnCoding.s.c}
 * @brief:LdpcEnCoding
 * @author: ${liang.wang}
 * COPYRIGHT NOTICE: (c) smartlogictech. All rights reserved.
 * Version      Change_date         Owner         Change_content
   1.0           2021/12/27       liang.wang       create file
   1.1           2022/01/13       liang.wang       Add Zclen = 104,208 case
   1.2           2022/02/07       liang.wang       Add Ldpc64BG1 case
*****************************************************************/

#include <LDPCEncoding.h>
#include "ucps2.h"
#include "ucp2_utils.h"


void Ldpc64BG1(int* ConfigBaseAddr, int InputAddr,int Zclen,int HMatrixAddr,int TempAddr0,int TempAddr1,int TempAddr2) {
	int *Para = ConfigBaseAddr;
	Para[0] = (((Zclen*22) + 63) >> 6);//bit -> byte cyc
	Para[2] = (((Zclen*66) + 63) >> 6);//byte -> bit cyc
	if(Zclen == 13 || Zclen == 26 || Zclen == 52) {
		Para[3] = 0;
	} else {
		Para[3] = 1;
	}

	Para[16*1+0] = Zclen;
	//input bit Data
	Para[16*3+0] = InputAddr;

	//output byte Data
	Para[16*4+0] = TempAddr0;
	Para[16*4+12] = Zclen*22;

	//input byte Data
	Para[16*5+0] = TempAddr0;
	Para[16*5+4] = Zclen;

	//input H_BG 1,3,5:21
	Para[16*6+0] = HMatrixAddr;

	//input H_BG 2,4,22:46
	Para[16*7+0] = HMatrixAddr+0x116;

	//output H_Pre 1,3,5:21
	Para[16*8+0] = TempAddr1;
	Para[16*8+12] = 0x116;//BG1 Case

	//output H_Pre 2,4,22:46
	Para[16*9+0] = TempAddr2;
	Para[16*9+12] = 0x10e;//BG1 Case

	//input H_Pre 1,3,5:21
	Para[16*14+0] = TempAddr1;

	//input H_Pre 2,4,22:46
	Para[16*15+0] = TempAddr2;

	//output W0 W1 W2 W3 W4~W20 (Byte) -> BIU2.T2
	Para[16*16+0] = TempAddr0 + Zclen*22;
	Para[16*16+4] = Zclen;
	Para[16*16+12] = Zclen*21;
	Para[16*16+13] = ( (0x100 + Zclen) << 16) + 6;

	//output W21-W45 (Byte)  -> BIU3.T2
	Para[16*17+0] = TempAddr0 + Zclen*(22+21);
	Para[16*17+4] = Zclen;
	Para[16*17+12] = Zclen*25;
	Para[16*17+13] = ( (0x100 + Zclen) << 16) + 6;

	if (Zclen == 32) {
		Para[16*16+14] = 0xffffffff;
		Para[16*16+15] = 0;
		Para[16*17+14] = 0xffffffff;
		Para[16*17+15] = 0;
	}else if(Zclen > 32) {
		Para[16*16+14] = 0xffffffff;
		Para[16*16+15] = (1 << (Zclen-32)) - 1;
		Para[16*17+14] = 0xffffffff;
		Para[16*17+15] = (1 << (Zclen-32)) - 1;
	} else {
		Para[16*16+14] = (1 << Zclen) - 1;
		Para[16*16+15] = 0;
		Para[16*17+14] = (1 << Zclen) - 1;
		Para[16*17+15] = 0;
	}

	//input Byte change to Bit
	Para[16*18+0] = TempAddr0 + Zclen*2;//

	//output LDPCEncoding Bit
	Para[16*19+0] = InputAddr;
	Para[16*19+12] = ((Zclen*66 + 7) >> 3);

	return;

}


void Ldpc64BG2(int* ConfigBaseAddr, int InputAddr,int Zclen,int HMatrixAddr,int TempAddr0,int TempAddr1,int TempAddr2) {
	int *Para = ConfigBaseAddr;
	Para[0] = (((Zclen*10) + 63) >> 6);//bit -> byte cyc
	Para[3] = (((Zclen*50) + 63) >> 6);//byte -> bit cyc
	if(Zclen == 7 || Zclen == 14 || Zclen == 28 || Zclen == 56 || Zclen == 15 || Zclen == 30 || Zclen == 60 ) {
		Para[4] = 0;
	} else {
		Para[4] = 1;
	}

	Para[16*1+0] = Zclen;
	//input bit Data
	Para[16*3+0] = InputAddr;

	//output byte Data
	Para[16*4+0] = TempAddr0;
	Para[16*4+12] = Zclen*22;

	//input byte Data
	Para[16*5+0] = TempAddr0;
	Para[16*5+4] = Zclen;

	//input H_BG 1,2,5:20
	Para[16*6+0] = HMatrixAddr;

	//input H_BG 3,4,21:42
	Para[16*7+0] = HMatrixAddr+0x96;

	//output H_Pre 1,2,5:20
	Para[16*8+0] = TempAddr1;
	Para[16*8+12] = 0x96;

	//output H_Pre 3,4,21:42
	Para[16*9+0] = TempAddr2;
	Para[16*9+12] = 0x96;

	//input H_Pre 1,3,5:21
	Para[16*14+0] = TempAddr1;

	//input H_Pre 2,4,22:46
	Para[16*15+0] = TempAddr2;

	//output W0 W1 W2 W3 W4~W19 (Byte) -> BIU2.T2
	Para[16*16+0] = TempAddr0 + Zclen*10;
	Para[16*16+4] = Zclen;
	Para[16*16+12] = Zclen*20;
	Para[16*16+13] = ( (0x100 + Zclen) << 16) + 6;

	//output W21-W42 (Byte)  -> BIU3.T2
	Para[16*17+0] = TempAddr0 + Zclen*(10+20);
	Para[16*17+4] = Zclen;
	Para[16*17+12] = Zclen*22;
	Para[16*17+13] = ( (0x100 + Zclen) << 16) + 6;

	if (Zclen == 32) {
		Para[16*16+14] = 0xffffffff;
		Para[16*16+15] = 0;
		Para[16*17+14] = 0xffffffff;
		Para[16*17+15] = 0;
	}else if(Zclen > 32) {
		Para[16*16+14] = 0xffffffff;
		Para[16*16+15] = (1 << (Zclen-32)) - 1;
		Para[16*17+14] = 0xffffffff;
		Para[16*17+15] = (1 << (Zclen-32)) - 1;
	} else {
		Para[16*16+14] = (1 << Zclen) - 1;
		Para[16*16+15] = 0;
		Para[16*17+14] = (1 << Zclen) - 1;
		Para[16*17+15] = 0;
	}

	//input Byte change to Bit
	Para[16*18+0] = TempAddr0 + Zclen*2;//

	//output LDPCEncoding Bit
	Para[16*19+0] = InputAddr;
	Para[16*19+12] = ((Zclen*50 + 7) >> 3);

	return;

}

void Ldpc384Pre(int* ConfigBaseAddr,int InputAddr,int Zclen,int Basegraph,int OutputAddr0,int OutputAddr1){

	int *Para = ConfigBaseAddr;
	int Hstep = 0;
	if (Basegraph == 1) {//BG1 Case
		Para[0] = 3;//ceil(139/64)
		Hstep = 0x116;//139 * 2
		Para[16*3+12] = 0x22c; //139*4 byte
		Para[16*4+12] = 0x21c; //135*4
	} else {
		Para[0] = 2;//ceil(75/64)
		Hstep = 0x96;// 75 * 2
		Para[16*3+12] = 0x12c; //75*4 byte
		Para[16*4+12] = 0x12c; //75*4 byte
	}

    //BG1 H 1 3 5:21  ;   BG2 H 1 2 5:20
	Para[16+0] = InputAddr;
	//BG1 H 2 4 22:46 ;   BG2 H 3 4 21:42
	Para[16*2+0] = InputAddr+Hstep;
	//out [0xBit.shift Byte.shift] part1
	Para[16*3+0] = OutputAddr0;
	//out [0xBit.shift Byte.shift] part2
	Para[16*4+0] = OutputAddr1;
	//Zclen
	Para[16*5+0] = Zclen;

	return;

}
void Ldpc384BG1(int* ConfigBaseAddr,int InputAddr0,int InputAddr1,int InputAddr2,int Zclen){

	int *Para = ConfigBaseAddr;

	if(Zclen == 104 || Zclen == 208) {
		Para[1] = 0;
	} else {
		Para[1] = 1;
	}
	//Input Data
	Para[16+0] = InputAddr0;
	Para[16+4] = (Zclen>>3);

	//input [0xBit.shift Byte.shift] part1
	Para[16*2+0] = InputAddr1;

	//input [0xBit.shift Byte.shift] part2
	Para[16*3+0] = InputAddr2;

	//Zclen(Byte)
	Para[16*4+0] = (Zclen>>3);

	//Output 1-4 5-21 BIU2
	Para[16*8+0] = InputAddr0 + 22*(Zclen>>3);
	Para[16*8+4] = (Zclen>>3);
	Para[16*8+12] = (Zclen>>3)*21;//KBNum
	Para[16*8+13] = ( (0x100 + (Zclen>>3)) << 16) + 6;

	//Output 22-46 BIU3
	Para[16*9+0] = InputAddr0 + (Zclen>>3)*(22+21);
	Para[16*9+4] = (Zclen>>3);
	Para[16*9+12] = (Zclen>>3)*25;//KBNum
	Para[16*9+13] = ( (0x100 + (Zclen>>3)) << 16) + 6;

	if (Zclen == 256) {
		Para[16*8+14] = 0xffffffff;
		Para[16*8+15] = 0;
		Para[16*9+14] = 0xffffffff;
		Para[16*9+15] = 0;
	} else if (Zclen < 256){
		Para[16*8+14] = (1 << (Zclen>>3)) - 1;
		Para[16*8+15] = 0;
		Para[16*9+14] = (1 << (Zclen>>3)) - 1;
		Para[16*9+15] = 0;
	} else {
		Para[16*8+14] = 0xffffffff;
		Para[16*8+15] = 0xffffffff;
		Para[16*9+14] = 0xffffffff;
		Para[16*9+15] = 0xffffffff;
	}

	return;

}

void Ldpc384BG2(int* ConfigBaseAddr,int InputAddr0,int InputAddr1,int InputAddr2,int Zclen){

	int *Para = ConfigBaseAddr;

	if(Zclen == 112 || Zclen == 224 || Zclen == 120 || Zclen == 240) {
		Para[2] = 0;
	} else {
		Para[2] = 1;
	}

	//Input Data
	Para[16+0] = InputAddr0;
	Para[16+4] = (Zclen>>3);

	//input [0xBit.shift Byte.shift] part1
	Para[16*2+0] = InputAddr1;

	//input [0xBit.shift Byte.shift] part2
	Para[16*3+0] = InputAddr2;

	//Zclen(Byte)
	Para[16*4+0] = (Zclen>>3);

	//Output 1-4 5-21 BIU2
	Para[16*8+0] = InputAddr0 + 10*(Zclen>>3);
	Para[16*8+4] = (Zclen>>3);
	Para[16*8+12] = (Zclen>>3)*20;//KBNum
	Para[16*8+13] = ( (0x100 + (Zclen>>3)) << 16) + 6;

	//Output 22-46 BIU3
	Para[16*9+0] = InputAddr0 + (Zclen>>3)*(10+20);
	Para[16*9+4] = (Zclen>>3);
	Para[16*9+12] = (Zclen>>3)*22;//KBNum
	Para[16*9+13] = ( (0x100 + (Zclen>>3)) << 16) + 6;

	if (Zclen == 256) {
		Para[16*8+14] = 0xffffffff;
		Para[16*8+15] = 0;
		Para[16*9+14] = 0xffffffff;
		Para[16*9+15] = 0;
	} else if (Zclen < 256){
		Para[16*8+14] = (1 << (Zclen>>3)) - 1;
		Para[16*8+15] = 0;
		Para[16*9+14] = (1 << (Zclen>>3)) - 1;
		Para[16*9+15] = 0;
	} else {
		Para[16*8+14] = 0xffffffff;
		Para[16*8+15] = 0xffffffff;
		Para[16*9+14] = 0xffffffff;
		Para[16*9+15] = 0xffffffff;
	}
	return;

}
