/*
 * Dependency control scoreboard kernel for MBAFF frame
 * Copyright © <2010>, Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * This file was originally licensed under the following license
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
// Kernel name: scoreboard_MBAFF.asm
//
// Dependency control scoreboard kernel for MBAFF frame
//
//  $Revision: 16 $
//  $Date: 10/18/06 4:10p $
//

// ----------------------------------------------------
//  Main: scoreboard_MBAFF
// ----------------------------------------------------
// ----------------------------------------------------
//  Scoreboard structure
// ----------------------------------------------------
//
//	1 DWORD per thread
//
//	Bit 31:	"Checking" thread, i.e. an intra MB that sends "check dependency" message
//	Bit 30: "Completed" thread. This bit set by an "update" message from intra/inter MB.
//	Bits 29:28:	Must set to 0
//	Bits 27:24:	EUID
//	Bits 23:18: Reserved
//	Bits 17:16: TID
//	Bits 15:8:	X offset of current MB
//	Bits 15:5:	Reserved
//	Bits 4:0: 5 bits of available neighbor MB flags

.kernel scoreboard_MBAFF
SCOREBOARD_MBAFF:

#ifdef _DEBUG
// WA for FULSIM so we'll know which kernel is being debugged
mov (1) acc0:ud 0xffaa55a5:ud
#endif

#include "header.inc"
#include "scoreboard_header.inc"

//
//  Now, begin source code....
//

.code

#ifdef	AS_ENABLED
	and.z.f0.1	(1)	NULLREG	r0.2<0;1,0>:ud	TH_RES	// Is this a restarted thread previously interrupted?
	(f0.1) jmpi	(1)	MBAFF_Scoreboard_Init

	#include "scoreboard_restore_AS.asm"

	jmpi (1)	MBAFF_Scoreboard_OpenGW
MBAFF_Scoreboard_Init:
#endif	// End AS_ENABLED

// Scoreboard must be initialized to 0xc000ffff, meaning all "completed"
// And it also avoids message mis-handling for the first MB
    $for(0; <32; 2) {
	mov (16)	CMD_SB(%1)<1>	0xc000ffff:ud {Compr}
	}
#ifdef	DOUBLE_SB					// Scoreboard size needs to be doubled
    $for(32; <64; 2) {
	mov (16)	CMD_SB(%1)<1>	0xc000ffff:ud {Compr}
	}
#endif	// DOUBLE_SB

//----------------------------------------------------------
//	Open message gateway for the scoreboard thread
//
//	RegBase = r4 (0x04)
//	Gateway Size = 64 GRF registers (0x6)
//	Dispatch ID = r0.20:ub
//	Scoreboard Thread Key = 0
//----------------------------------------------------------
MBAFF_Scoreboard_OpenGW:
    mov (8)	MSGHDRY0<1>:ud	0x00000000:ud			// Initialize message header payload with 0

	// Send a message with register base RegBase=0x04(r4) and Gateway size = 0x6 = 64 GRF reg and Key = 0
	// 000 00000100 00000 00000 110 00000000 ==> 0000 0000 1000 0000 0000 0110 0000 0000
#ifdef	AS_ENABLED
	add (1) MSGHDRY0.5<1>:ud r0.20:ub	0x00800700:ud	// Allocate 128 GRFs for message gateway - for SIP to send notification MSG
#else
  #ifdef	DOUBLE_SB
	add (1) MSGHDRY0.5<1>:ud r0.20:ub	0x00800600:ud	// 64 GRF's for CTG-B
  #else
	add (1) MSGHDRY0.5<1>:ud r0.20:ub	0x00800500:ud	// 32 GRF's for CTG-A
  #endif	// DOUBLE_SB
#endif

	send (8)	NULLREG  MSGHDRY0	null:ud    MSG_GW	OGWMSGDSC

//------------------------------------------------------------------------
//	Send Thread Spawning Message to start dispatching macroblock threads
//
//------------------------------------------------------------------------
#ifdef	AS_ENABLED
	mov (8)	acc0<1>:ud	CMD_SB(31)<8;8,1>			// Ensure scoreboard data have been completely restored
#endif	// End AS_ENABLED
    mov (8)	MSGHDRY1<1>:ud		r0<8;8,1>:ud		// Initialize message header payload with R0
    mov (1)	MSGHDRY1.4<1>:ud	0x00000400:ud		// Dispatch URB length = 1

	send (8)	NULLREG  MSGHDRY1	null:ud    TS	TSMSGDSC

    mov (8)	MSGHDRY0<1>:ud		0x00000000:ud		// Initialize message header payload with 0

//------------------------------------------------------------------------
//	Scoreboard control data initialization
//------------------------------------------------------------------------
#ifdef	AS_ENABLED
	or	(1)	cr0.1:ud	cr0.1:ud	AS_INT_EN		// Enable interrupt
	(f0.1) jmpi	(1)	MBAFF_Scoreboard_State_Init	// Jump if not restarted thread

	// Restore scoreboard kernel control data to r1 - r3
    mov (1)	m4.1:ud	64:ud				// Starting r1
    mov (1)	m4.2:ud	0x0002001f:ud		// for 3 registers
    send (8)	r1.0<1>:ud	m4	null:ud	DWBRMSGDSC_SC+0x00030000+AS_SAVE	// Restore r1 - r3
	and (1)	CMDPTR<1>:uw	MBINDEX(0)<0;1,0>	SB_MASK*4:uw 	// Restore scoreboard entries for current MB

// EOT if all MBs have been decoded
	cmp.e.f0.0 (1)	NULLREG	TotalMB<0;1,0>:w	0:w	// Set "Last MB" flag
	(-f0.0) jmpi (1)	MBAFF_Before_First_MB
    END_THREAD

// Check whether it is before the first MB
MBAFF_Before_First_MB:
	cmp.e.f0.0 (1)	NULLREG	AVAILFLAGD<1>:ud	0x08020401:ud	// in ACBD order
	(f0.0) jmpi (1)	MBAFF_Wavefront_Walk

MBAFF_Scoreboard_State_Init:
#endif	// End AS_ENABLED
	mov (2) WFLen_B<2>:w		HEIGHTINMB_1<0;1,0>:w
	mov (1)	AVAILFLAGD<1>:ud	0x08020401:ud	// in ACBD order
	mov (1)	AVAILFLAG1D<1>:ud	0x08020410:ud	// in A_C_B_D_ order
	mov	(1) CASE00PTR<1>:ud	MBAFF_Notify_MSG_IP-MBAFF_No_Message_IP:ud		// Inter kernel starts
	mov	(1) CASE10PTR<1>:ud	MBAFF_Dependency_Check_IP-MBAFF_No_Message_IP:ud	// Intra kernel starts
#ifdef	AS_ENABLED
	mov	(1) CASE11PTR<1>:ud	0:ud		// No message
#else
	mov	(1) CASE11PTR<1>:ud	MBAFF_MB_Loop_IP-MBAFF_No_Message_IP:ud		// No message
#endif	// End AS_ENABLED
	mov	(1) StartXD<1>:ud	0:ud
	mov	(1) NewWFOffsetD<1>:ud	0x01ffff00:ud

	mov (8) WFStart_T(0)<1>	0xffff:w
	mov (1) WFStart_T(0)<1>	0:w

	mov	(8)	a0.0<1>:uw	0x0:uw						// Initialize all pointers to 0

//------------------------------------------------------------------------
//	Scoreboard message handling loop
//------------------------------------------------------------------------
//
MBAFF_Scoreboard_Loop:
// Calculate current wavefront length (same for top and bottom MB wavefronts)
	add.ge.f0.1 (16)	acc0<1>:w	StartX<0;1,0>:w	0:w	// Used for x>2*y check
	mac.g.f0.0 (16)	NULLREGW	WFLenY<0;1,0>:w	-2:w	// X - 2*Y > 0 ??
	(f0.0) mov (2)	WFLen_B<1>:w	WFLenY<0;1,0>:w		// Use smaller vertical wavefront length
	(f0.0) mov (1)	WFLen_Save<1>:w	WFLenY<0;1,0>:w		// Save current wave front length
	(-f0.0) asr.sat (2)	WFLen_B<1>:uw	StartX<0;1,0>:w	1:w	// Horizontal wavefront length is smaller
	(-f0.0) asr.sat (1)	WFLen_Save<1>:uw	StartX<0;1,0>:w	1:w	// Save current wave front length

// Initialize 9-MB group for top macroblock wavefront
#ifdef ONE_MB_WA_MBAFF
	mov (2) MBINDEX(0)<1>		WFStart_T(0)<2;2,1>
	(f0.1) add (4) MBINDEX(0,2)<1>		WFStart_B(0,1)<4;4,1>	-1:w
	(-f0.1) add (4) MBINDEX(0,2)<1>		WFStart_B(0,0)<4;4,1>	-1:w
	mov (1) MBINDEX(0,5)<1>		WFStart_B(0,1)<0;1,0>
	(-f0.1) mov (1) StartX<1>:w		0:w					// WA for 1-MB wide pictures
#else
	mov (2) MBINDEX(0)<1>		WFStart_T(0)<2;2,1>			{NoDDClr}
	add (4) MBINDEX(0,2)<1>		WFStart_B(0,1)<4;4,1>	-1:w	{NoDDChk,NoDDClr}
	mov (1) MBINDEX(0,5)<1>		WFStart_B(0,1)<0;1,0>		{NoDDChk,NoDDClr}
	add (4) MBINDEX(0,6)<1>		WFStart_T(0,1)<4;4,1>	-1:w	{NoDDChk}	// Upper MB group (C_B_D_x)
#endif

// Update WFStart_B[0]
	add (8)	acc0<1>:w	WFLen<0;1,0>:w	1:w				// WFLen + 1
	add (1)	WFStart_B(0,0)<1>	acc0<0;1,0>:w	WFStart_T(0,0)<0;1,0>	// WFStart_T[0] + WFLen + 1

MBAFF_Start_Wavefront:
	mul (16)	MBINDEX(0)<1>	MBINDEX(0)REGION(16,1)	4:w		// Adjust MB order # to be DWORD aligned
	and (1)	CMDPTR<1>:uw	acc0<0;1,0>:w	SB_MASK*4:uw 	// Wrap around scoreboard entries for current MB

MBAFF_Wavefront_Walk:
	wait	n0:ud

//	Check for combined "checking" or "completed" threads in forwarded message
//	2 MSB of scoreboard message indicate:
//	0b00 = "inter start" message
//	0b10 = "intra start" message
//	0b11 = "No Message" or "inter complete" message
//	0b01 = Reserved (should never occur)
//
MBAFF_MB_Loop:
	shr	(1)	PMSGSEL<1>:uw	r[CMDPTR,CMD_SB_REG_OFF*GRFWIB+2]<0;1,0>:uw	12:w					// DWORD aligned pointer to message handler
	and.nz.f0.1 (8) NULLREG	r[CMDPTR,CMD_SB_REG_OFF*GRFWIB]<0;1,0>:ub	AVAILFLAG<8;8,1>:ub		// f0.1 8 LSB will have the available flags in ACBDA_C_B_D_ order
	mov (1) MSGHDRY0.4<1>:ud	r[CMDPTR,CMD_SB_REG_OFF*GRFWIB]<0;1,0>:ud		// Copy MB thread info from scoreboard
	jmpi (1)	r[PMSGSEL, INLINE_REG_OFF*GRFWIB+16]<0;1,0>:d

//	Now determine whether this is "inter done" or "no message"
//	through checking debug_counter
//
MBAFF_No_Message:
#ifdef	AS_ENABLED
	cmp.z.f0.1 (1)	NULLREG	n0:ud	0	// Are all messages handled?
	and.z.f0.0 (1)	NULLREG	cr0.1:ud	AS_INT	// Poll interrupt bit
	(-f0.1) jmpi (1)	MBAFF_MB_Loop			// Continue polling the remaining message from current thread

// All messages have been handled
	(f0.0) jmpi (1) MBAFF_Wavefront_Walk		// No interrupt occurs. Wait for next one

// Interrupt has been detected
// Save all contents and terminate the scoreboard
//
	#include "scoreboard_save_AS.asm"

	// Save scoreboard control data as well
	//
    mov (1)	MSGHDR.1:ud		64:ud
    mov (1)	MSGHDR.2:ud		0x0002001f:ud	// for 3 registers
	$for(0; <3; 1) {
	mov (8)	MSGPAYLOADD(%1)<1>	CMD_SB(%1-3)REGION(8,1)
	}
    send (8)	NULLREG	MSGHDR	null:ud	DWBWMSGDSC+0x00300000+AS_SAVE	// Save r1 - r3

	send (8) NULLREG MSGHDR r0:ud EOTMSGDSC+TH_INT	// Terminate with "Thread Interrupted" bit set
#endif	// End AS_ENABLED

MBAFF_Dependency_Check:
//	Current thread is "checking" but not "completed" (0b10 case).
//	Check for dependency clear using all availability bits
//
	and (8)	DEPPTR<1>:uw	MBINDEX(0,1)REGION(8,1)	SB_MASK*4:uw	// Wrap around scoreboard entries for current MB
MBAFF_Dependency_Polling:
	(f0.1) and.z.f0.1 (8)	NULLREG	r[DEPPTR,CMD_SB_REG_OFF*GRFWIB+3]<1,0>:ub	DONEFLAG:uw	// f0.1 8 LSB contains dependency clear
	(f0.1.any8h) jmpi (1)	MBAFF_Dependency_Polling		// Dependency not clear, keep polling..

//	"Checking" thread and dependency cleared, send a message to let the thread go
//
MBAFF_Notify_MSG:
	send (8)	NULLREG  MSGHDRY0	null:ud    MSG_GW	FWDMSGDSC+NOTIFYMSG

//	Current macroblock has been serviced. Update to next macroblock in special zig-zag order
//
MBAFF_Update_CurMB:
	add.ge.f0.0 (2)	TotalMB<2>:w	TotalMB<4;2,2>:w	-1:w 	// Set "End of wavefront" flag and decrement "TotalMB"
	add (16)	MBINDEX(0)<1>	MBINDEX(0)REGION(16,1)	4:w		// Increment MB indices
	and (1)	CMDPTR<1>:uw	acc0<0;1,0>:w	SB_MASK*4:uw // Wrap around scoreboard entries for current MB
	(f0.0.all2h) jmpi (1) MBAFF_Wavefront_Walk	// Continue wavefront walking

// Top macroblock wavefront walk done, start bottom MB wavefront
	add.ge.f0.0 (1)	WFLen<1>:w	WFLen_B<0;1,0>:w	0:w	{NoDDClr}		// Set bottom MB wavefront length
	mov (1)	WFLen_B<1>:w	-1:w	{NoDDChk}			// Reset bottom MB wavefront length
	
// Initialize 9-MB group for bottom macroblock wavefront
	mov (8) MBINDEX(0)<1>		WFStart_B(0)<1;4,0>			{NoDDClr}	// Initialize with WFStart_B[0] and WFStart_B[1]
	mov (4) MBINDEX(0,1)<1>		WFStart_T(0,1)<0;1,0>		{NoDDChk,NoDDClr}	// Initialize with WFStart_T[1]
	mov (2) MBINDEX(0,2)<1>		WFStart_T(0)<0;1,0>			{NoDDChk,NoDDClr}	// Initialize with WFStart_T[0]
	add (4) MBINDEX(0,6)<1>		WFStart_B(0,1)<4;4,1>	-1:w	{NoDDChk}	// Upper MB group (C_B_D_x)

	(f0.0) jmpi (1) MBAFF_Start_Wavefront				// Start bottom MB wavefront walk

//	Start new wavefront
//
	cmp.e.f0.1 (16)	NULLREGW  StartX<0;1,0>:uw	WIDTHINMB_1<0;1,0>:uw	// Set "on picture right boundary" flag

	// Update WFStart_T and WFStart_B
	add (8)	acc0<1>:w	WFStart_T(0)REGION(1,0)	1:w				// Move WFStart_T[0]+1 to acc0 to remove dependency later
	mov (8)	WFStart_T(0,1)<1>	WFStart_T(0)<8;8,1>	{NoDDClr}	// Shift WFStart_T(B)[0:2] to WFStart_T(B)[1:3]
	mac (1)	WFStart_T(0,0)<1>	WFLen_Save<0;1,0>:w	2:w {NoDDChk}	// WFStart_T[0] = WFStart_T[0] + 2*WFLen

	cmp.e.f0.0 (1)	NULLREG	TotalMB<0;1,0>:w	0:w	// Set "Last MB" flag

	(f0.1) add (4)	WFLen<1>:w	WFLen<4;4,1>:w	NewWFOffset<4;4,1>:b	// + (0, -1, -1, 1)
	(f0.1) add (8)	WFStart_T(0)<1>	WFStart_T(0)REGION(4,1)	1:w
	(-f0.1) add (1)	StartX<1>:w		StartX<0;1,0>:w	1:w		// Move to right MB
	(-f0.1) add (1)	WFStart_T(0)<1>	WFStart_T(0)REGION(1,0)	1:w

	(-f0.0) jmpi (1)	MBAFF_Scoreboard_Loop				// Not last MB, start new wavefront walking

// All MBs have decoded. Terminate the thread now
//
    END_THREAD

#if !defined(COMBINED_KERNEL)		// For standalone kernel only
.end_code

.end_kernel
#endif

// End of scoreboard_MBAFF
