/* * tbidefr.S * * Copyright (C) 2009, 2012 Imagination Technologies. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * * Routing deferred exceptions */ #include <asm/metag_regs.h> #include <asm/tbx.h> .text .balign 4 .global ___TBIHandleDFR .type ___TBIHandleDFR,function /* D1Ar1:D0Ar2 -- State * D0Ar3 -- SigNum * D0Ar4 -- Triggers * D1Ar5 -- InstOrSWSId * D0Ar6 -- pTBI (volatile) */ ___TBIHandleDFR: #ifdef META_BUG_MBN100212 MSETL [A0StP++], D0FrT, D0.5 /* D1Ar1,D0Ar2,D1Ar5,D0Ar6 -- Arguments to handler, must be preserved * D0Ar4 -- The deferred exceptions * D1Ar3 -- As per D0Ar4 but just the trigger bits * D0.5 -- The bgnd deferred exceptions * D1.5 -- TXDEFR with bgnd re-added */ /* - Collect the pending deferred exceptions using TXSTAT, * (ack's the bgnd exceptions as a side-effect) * - Manually collect remaining (interrupt) deferred exceptions * using TXDEFR * - Replace the triggers (from TXSTATI) with the int deferred * exceptions DEFR ..., TXSTATI would have returned if it was valid * from bgnd code * - Reconstruct TXDEFR by or'ing bgnd deferred exceptions (except * the DEFER bit) and the int deferred exceptions. This will be * restored later */ DEFR D0.5, TXSTAT MOV D1.5, TXDEFR ANDT D0.5, D0.5, #HI(0xFFFF0000) MOV D1Ar3, D1.5 ANDT D1Ar3, D1Ar3, #HI(0xFFFF0000) OR D0Ar4, D1Ar3, #TXSTAT_DEFER_BIT OR D1.5, D1.5, D0.5 /* Mask off anything unrelated to the deferred exception triggers */ ANDT D1Ar3, D1Ar3, #HI(TXSTAT_BUSERR_BIT | TXSTAT_FPE_BITS) /* Can assume that at least one exception happened since this * handler wouldnt have been called otherwise. * * Replace the signal number and at the same time, prepare * the mask to acknowledge the exception * * D1Re0 -- The bits to acknowledge * D1Ar3 -- The signal number * D1RtP -- Scratch to deal with non-conditional insns */ MOVT D1Re0, #HI(TXSTAT_FPE_BITS & ~TXSTAT_FPE_DENORMAL_BIT) MOV D1RtP, #TXSTAT_FPE_INVALID_S FFB D1Ar3, D1Ar3 CMP D1Ar3, #TXSTAT_FPE_INVALID_S MOVLE D1Ar3, D1RtP /* Collapse FPE triggers to a single signal */ MOV D1RtP, #1 LSLGT D1Re0, D1RtP, D1Ar3 /* Get the handler using the signal number * * D1Ar3 -- The signal number * D0Re0 -- Offset into TBI struct containing handler address * D1Re0 -- Mask of triggers to keep * D1RtP -- Address of handler */ SUB D1Ar3, D1Ar3, #(TXSTAT_FPE_INVALID_S - TBID_SIGNUM_FPE) LSL D0Re0, D1Ar3, #2 XOR D1Re0, D1Re0, #-1 /* Prepare mask for acknowledge (avoids stall) */ ADD D0Re0,D0Re0,#TBI_fnSigs GETD D1RtP, [D0Ar6+D0Re0] /* Acknowledge triggers */ AND D1.5, D1.5, D1Re0 /* Restore remaining exceptions * Do this here in case the handler enables nested interrupts * * D1.5 -- TXDEFR with this exception ack'd */ MOV TXDEFR, D1.5 /* Call the handler */ SWAP D1RtP, PC GETL D0.5, D1.5, [--A0StP] GETL D0FrT, D1RtP, [--A0StP] MOV PC,D1RtP #else /* META_BUG_MBN100212 */ /* D1Ar1,D0Ar2,D1Ar5,D0Ar6 -- Arguments to handler, must be preserved * D0Ar4 -- The deferred exceptions * D1Ar3 -- As per D0Ar4 but just the trigger bits */ /* - Collect the pending deferred exceptions using TXSTAT, * (ack's the interrupt exceptions as a side-effect) */ DEFR D0Ar4, TXSTATI /* Mask off anything unrelated to the deferred exception triggers */ MOV D1Ar3, D0Ar4 ANDT D1Ar3, D1Ar3, #HI(TXSTAT_BUSERR_BIT | TXSTAT_FPE_BITS) /* Can assume that at least one exception happened since this * handler wouldnt have been called otherwise. * * Replace the signal number and at the same time, prepare * the mask to acknowledge the exception * * The unusual code for 1<<D1Ar3 may need explanation. * Normally this would be done using 'MOV rs,#1' and 'LSL rd,rs,D1Ar3' * but only D1Re0 is available in D1 and no crossunit insns are available * Even worse, there is no conditional 'MOV r,#uimm8'. * Since the CMP proves that D1Ar3 >= 20, we can reuse the bottom 12-bits * of D1Re0 (using 'ORGT r,#1') in the knowledge that the top 20-bits will * be discarded without affecting the result. * * D1Re0 -- The bits to acknowledge * D1Ar3 -- The signal number */ MOVT D1Re0, #HI(TXSTAT_FPE_BITS & ~TXSTAT_FPE_DENORMAL_BIT) MOV D0Re0, #TXSTAT_FPE_INVALID_S FFB D1Ar3, D1Ar3 CMP D1Ar3, #TXSTAT_FPE_INVALID_S MOVLE D1Ar3, D0Re0 /* Collapse FPE triggers to a single signal */ ORGT D1Re0, D1Re0, #1 LSLGT D1Re0, D1Re0, D1Ar3 SUB D1Ar3, D1Ar3, #(TXSTAT_FPE_INVALID_S - TBID_SIGNUM_FPE) /* Acknowledge triggers and restore remaining exceptions * Do this here in case the handler enables nested interrupts * * (x | y) ^ y == x & ~y. It avoids the restrictive XOR ...,#-1 insn * and is the same length */ MOV D0Re0, TXDEFR OR D0Re0, D0Re0, D1Re0 XOR TXDEFR, D0Re0, D1Re0 /* Get the handler using the signal number * * D1Ar3 -- The signal number * D0Re0 -- Address of handler */ LSL D0Re0, D1Ar3, #2 ADD D0Re0,D0Re0,#TBI_fnSigs GETD D0Re0, [D0Ar6+D0Re0] /* Tailcall the handler */ MOV PC,D0Re0 #endif /* META_BUG_MBN100212 */ .size ___TBIHandleDFR,.-___TBIHandleDFR /* * End of tbidefr.S */