// Filename : idct.cpp
//
// This file was initially generated by SpaceStudio but is meant to be modified
// by the user.
#include "idct.h"
#include "spacecomp_pre_cpp.h"

// Do NOT move macros, functions and includes beginning with "spacecomp".

idct::idct(SPACECOMP_CTOR_PARAMS(idct, INDEX))
	: abstract_module(SPACECOMP_MBASE_ARGS(idct, INDEX))
	, SPACECOMP_START_ILIST(idct, INDEX)
	// Other initializers may go here
{
	SPACECOMP_THREAD(idct, INDEX, thread);
	request_stack(16 * 1024);
}

void idct::thread(SPACECOMP_THREAD_PARAMS(idct, INDEX, thread)) {
	spacecomp_thread_initialize();

	idct_input_struct input;
	int Y[BLOCK_SIZE];
	SPACE_ALIGNED unsigned char Idct[BLOCK_SIZE];
	short row ,column;

	while (1) {
		const bool initializing = spacecomp_thread_loop_start();
		if (initializing) {
			// Perform your own initialization communications here as needed.
			// This happens every time the instance is reset, including on
			// initial startup.
			//
			// You may remove this "if" if you do not use it.
		}

		ModuleRead(MJPEG0_ID,SPACE_BLOCKING,&input);

		A: for (row = 0; row < BLOCK_HEIGHT; row++) {
			B: for (column = 0; column < BLOCK_WIDTH; column++)
				Y(row, column) = input.dataInput[row*BLOCK_WIDTH+column] << S_BITS;
			idct_1d(&Y(row, 0));
			/* Result Y is scaled up by factor sqrt(8)*2^S_BITS. */
		}

		C: for (column = 0; column < BLOCK_WIDTH; column++) {
			int Yc[BLOCK_HEIGHT];

			D: for (row = 0; row < BLOCK_HEIGHT; row++)
				Yc[row] = Y(row, column);

			idct_1d(Yc);

			E: for (row = 0; row < BLOCK_HEIGHT; row++) {
				/* Result is once more scaled up by a factor sqrt(8). */
				int r = 128 + descale(Yc[row], 2*S_BITS);
				/* Clip to 8 bits unsigned: */
				r = r > 0 ? (r < 255 ? r : 255) : 0;
				Idct_fnc(row, column) = r;
			}
		}

		//From HLS - NO optimization
		hw_compute_latency(680);
		ModuleWrite(MJPEG0_ID,SPACE_BLOCKING, (uint32_t*)Idct,BLOCK_SIZE/4);

	}
}

///////////////////////////////////////////////////////////////////////////////
///
/// rot
///
///////////////////////////////////////////////////////////////////////////////
void idct::rot(int f, int k, int x, int y, int* rx, int* ry) {
#define Cos(k)  COS[f][k]
#define Sin(k)  Cos(8-k)
	*rx = (Cos(k) * x - Sin(k) * y) >> C_BITS;
	*ry = (Sin(k) * x + Cos(k) * y) >> C_BITS;
#undef Cos
#undef Sin
}


///////////////////////////////////////////////////////////////////////////////
///
/// idct_1d
///
///////////////////////////////////////////////////////////////////////////////
void idct::idct_1d(int* Y) {
	// Variable
	int z1[8], z2[8], z3[8];

	/* Stage 1: */
	but(Y[0], Y[4], z1[1], z1[0]);
	rot(1, 6, Y[2], Y[6], &z1[2], &z1[3]);
	but(Y[1], Y[7], z1[4], z1[7]);
	z1[5] = (sqrt2 * Y[3]) >> C_BITS;
	z1[6] = (sqrt2 * Y[5]) >> C_BITS;

	/* Stage 2: */
	but(z1[0], z1[3], z2[3], z2[0]);
	but(z1[1], z1[2], z2[2], z2[1]);
	but(z1[4], z1[6], z2[6], z2[4]);
	but(z1[7], z1[5], z2[5], z2[7]);

	/* Stage 3: */
	z3[0] = z2[0];
	z3[1] = z2[1];
	z3[2] = z2[2];
	z3[3] = z2[3];
	rot(0, 3, z2[4], z2[7], &z3[4], &z3[7]);
	rot(0, 1, z2[5], z2[6], &z3[5], &z3[6]);

	/* Final stage 4: */
	but(z3[0], z3[7], Y[7], Y[0]);
	but(z3[1], z3[6], Y[6], Y[1]);
	but(z3[2], z3[5], Y[5], Y[2]);
	but(z3[3], z3[4], Y[4], Y[3]);
}

#include "spacecomp_post_cpp.h"
