/* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.
 *
 * Blackfin BF533/2.6 support : LG Soft India
 */


/* Include an exception handler to invoke the CPLB manager
 */

#include <asm-blackfin/linkage.h>
#include <asm/cplb.h>
#include <asm/entry.h>


.text

.globl _cplb_hdr;
.type _cplb_hdr, STT_FUNC;
.extern _cplb_mgr;
.type _cplb_mgr, STT_FUNC;
.extern __unknown_exception_occurred;
.type __unknown_exception_occurred, STT_FUNC;
.extern __cplb_miss_all_locked;
.type __cplb_miss_all_locked, STT_FUNC;
.extern __cplb_miss_without_replacement;
.type __cplb_miss_without_replacement, STT_FUNC;
.extern __cplb_protection_violation;
.type __cplb_protection_violation, STT_FUNC;
.extern panic_pv;

.align 2;

ENTRY(_cplb_hdr)
	SSYNC;
	[--SP] = ( R7:0, P5:0 );
	[--SP] = ASTAT;
	[--SP] = SEQSTAT;
	[--SP] = I0;
	[--SP] = I1;
	[--SP] = I2;
	[--SP] = I3;
	[--SP] = LT0;
	[--SP] = LB0;
	[--SP] = LC0;
	[--SP] = LT1;
	[--SP] = LB1;
	[--SP] = LC1;
	R2 = SEQSTAT;

	/*Mask the contents of SEQSTAT and leave only EXCAUSE in R2*/
	R2 <<= 26;
	R2 >>= 26;

	R1 = 0x23; /* Data access CPLB protection violation */
	CC = R2 == R1;
	IF !CC JUMP not_data_write;
	R0 = 2;		/* is a write to data space*/
	JUMP is_icplb_miss;

not_data_write:
	R1 = 0x2C; /* CPLB miss on an instruction fetch */
	CC = R2 == R1;
	R0 = 0;		/* is_data_miss == False*/
	IF CC JUMP is_icplb_miss;

	R1 = 0x26;
	CC = R2 == R1;
	IF !CC JUMP unknown;

	R0 = 1;		/* is_data_miss == True*/

is_icplb_miss:

#if ( defined (CONFIG_BLKFIN_CACHE) || defined (CONFIG_BLKFIN_DCACHE))
#if ( defined (CONFIG_BLKFIN_CACHE) && !defined (CONFIG_BLKFIN_DCACHE))
	R1 = CPLB_ENABLE_ICACHE;
#endif
#if ( !defined (CONFIG_BLKFIN_CACHE) && defined (CONFIG_BLKFIN_DCACHE))
	R1 = CPLB_ENABLE_DCACHE;
#endif
#if ( defined (CONFIG_BLKFIN_CACHE) && defined (CONFIG_BLKFIN_DCACHE))
	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
#endif
#else
	R1 = 0;
#endif

	[--SP] = RETS;
	CALL _cplb_mgr;
	RETS = [SP++];
	CC = R0 == 0;
	IF !CC JUMP not_replaced;
	LC1 = [SP++];
	LB1 = [SP++];
	LT1 = [SP++];
	LC0 = [SP++];
	LB0 = [SP++];
	LT0 = [SP++];
	I3 = [SP++];
	I2 = [SP++];
	I1 = [SP++];
	I0 = [SP++];
	SEQSTAT = [SP++];
	ASTAT = [SP++];
	( R7:0, P5:0 ) = [SP++];
	RTS;

unknown:
	[--SP] = RETS;
	CALL __unknown_exception_occurred;
	RETS = [SP++];
	JUMP unknown;
not_replaced:
	CC = R0 == CPLB_NO_UNLOCKED;
	IF !CC JUMP next_check;
	[--SP] = RETS;
	CALL __cplb_miss_all_locked;
	RETS = [SP++];
next_check:
	CC = R0 == CPLB_NO_ADDR_MATCH;
	IF !CC JUMP next_check2;
	[--SP] = RETS;
	CALL __cplb_miss_without_replacement;
	RETS = [SP++];
	JUMP not_replaced;
next_check2:
	CC = R0 == CPLB_PROT_VIOL;
	IF !CC JUMP strange_return_from_cplb_mgr;
	[--SP] = RETS;
	CALL __cplb_protection_violation;
	RETS = [SP++];
	JUMP not_replaced;
strange_return_from_cplb_mgr:
	IDLE;
	CSYNC;
	JUMP strange_return_from_cplb_mgr;

/************************************
 * Diagnostic exception handlers
 */

__cplb_miss_all_locked:
	sp += -12;
	R0 = CPLB_NO_UNLOCKED;
	call panic_bfin;
	SP += 12;
	RTS;

 __cplb_miss_without_replacement:
	sp += -12;
	R0 = CPLB_NO_ADDR_MATCH;
	call panic_bfin;
	SP += 12;
	RTS;

__cplb_protection_violation:
	sp += -12;
	R0 = CPLB_PROT_VIOL;
	call panic_bfin;
	SP += 12;
	RTS;

__unknown_exception_occurred:

	/* This function is invoked by the default exception
	 * handler, if it does not recognise the kind of
	 * exception that has occurred. In other words, the
	 * default handler only handles some of the system's
	 * exception types, and it does not expect any others
	 * to occur. If your application is going to be using
	 * other kinds of exceptions, you must replace the
	 * default handler with your own, that handles all the
	 * exceptions you will use.
	 *
	 * Since there's nothing we can do, we just loop here
	 * at what we hope is a suitably informative label.
	 */

	IDLE;
do_not_know_what_to_do:
	CSYNC;
	JUMP __unknown_exception_occurred;

	RTS;
.__unknown_exception_occurred.end:
.global __unknown_exception_occurred;
.type __unknown_exception_occurred, STT_FUNC;

panic_bfin:
	RTS;