Commit 027f891f authored by James Hogan's avatar James Hogan

metag: TBX source

Add source files from the Thread Binary Interface (TBI) library which
provides useful low level operations and traps/context management.

Among other things it handles interrupt/exception/syscall entry (in
tbipcx.S).
Signed-off-by: default avatarJames Hogan <james.hogan@imgtec.com>
parent 4ca151b2
/*
* tbicore.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* Core functions needed to support use of the thread binary interface for META
* processors
*/
.file "tbicore.S"
/* Get data structures and defines from the TBI C header */
#include <asm/metag_mem.h>
#include <asm/metag_regs.h>
#include <asm/tbx.h>
.data
.balign 8
.global ___pTBISegs
.type ___pTBISegs,object
___pTBISegs:
.quad 0 /* Segment list pointer with it's */
.size ___pTBISegs,.-___pTBISegs
/* own id or spin-lock location */
/*
* Return ___pTBISegs value specific to privilege level - not very complicated
* at the moment
*
* Register Usage: D0Re0 is the result, D1Re0 is used as a scratch
*/
.text
.balign 4
.global ___TBISegList
.type ___TBISegList,function
___TBISegList:
MOVT A1LbP,#HI(___pTBISegs)
ADD A1LbP,A1LbP,#LO(___pTBISegs)
GETL D0Re0,D1Re0,[A1LbP]
MOV PC,D1RtP
.size ___TBISegList,.-___TBISegList
/*
* Search the segment list for a match given Id, pStart can be NULL
*
* Register Usage: D1Ar1 is pSeg, D0Ar2 is Id, D0Re0 is the result
* D0Ar4, D1Ar3 are used as a scratch
* NB: The PSTAT bit if Id in D0Ar2 may be toggled
*/
.text
.balign 4
.global ___TBIFindSeg
.type ___TBIFindSeg,function
___TBIFindSeg:
MOVT A1LbP,#HI(___pTBISegs)
ADD A1LbP,A1LbP,#LO(___pTBISegs)
GETL D1Ar3,D0Ar4,[A1LbP] /* Read segment list head */
MOV D0Re0,TXSTATUS /* What priv level are we at? */
CMP D1Ar1,#0 /* Is pStart provided? */
/* Disable privilege adaption for now */
ANDT D0Re0,D0Re0,#0 /*HI(TXSTATUS_PSTAT_BIT) ; Is PSTAT set? Zero if not */
LSL D0Re0,D0Re0,#(TBID_PSTAT_S-TXSTATUS_PSTAT_S)
XOR D0Ar2,D0Ar2,D0Re0 /* Toggle Id PSTAT if privileged */
MOVNZ D1Ar3,D1Ar1 /* Use pStart if provided */
$LFindSegLoop:
ADDS D0Re0,D1Ar3,#0 /* End of list? Load result into D0Re0 */
MOVZ PC,D1RtP /* If result is NULL we leave */
GETL D1Ar3,D0Ar4,[D1Ar3] /* Read pLink and Id */
CMP D0Ar4,D0Ar2 /* Does it match? */
BNZ $LFindSegLoop /* Loop if there is no match */
TST D0Re0,D0Re0 /* Clear zero flag - we found it! */
MOV PC,D1RtP /* Return */
.size ___TBIFindSeg,.-___TBIFindSeg
/* Useful offsets to encode the lower bits of the lock/unlock addresses */
#define UON (LINSYSEVENT_WR_ATOMIC_LOCK & 0xFFF8)
#define UOFF (LINSYSEVENT_WR_ATOMIC_UNLOCK & 0xFFF8)
/*
* Perform a whole spin-lock sequence as used by the TBISignal routine
*
* Register Usage: D1Ar1 is pLock, D0Ar2 is Mask, D0Re0 is the result
* (All other usage due to ___TBIPoll - D0Ar6, D1Re0)
*/
.text
.balign 4
.global ___TBISpin
.type ___TBISpin,function
___TBISpin:
SETL [A0StP++],D0FrT,D1RtP /* Save our return address */
ORS D0Re0,D0Re0,#1 /* Clear zero flag */
MOV D1RtP,PC /* Setup return address to form loop */
$LSpinLoop:
BNZ ___TBIPoll /* Keep repeating if fail to set */
GETL D0FrT,D1RtP,[--A0StP] /* Restore return address */
MOV PC,D1RtP /* Return */
.size ___TBISpin,.-___TBISpin
/*
* Perform an attempt to gain access to a spin-lock and set some bits
*
* Register Usage: D1Ar1 is pLock, D0Ar2 is Mask, D0Re0 is the result
* !!On return Zero flag is SET if we are sucessfull!!
* A0.3 is used to hold base address of system event region
* D1Re0 use to hold TXMASKI while interrupts are off
*/
.text
.balign 4
.global ___TBIPoll
.type ___TBIPoll,function
___TBIPoll:
MOV D1Re0,#0 /* Prepare to disable ints */
MOVT A0.3,#HI(LINSYSEVENT_WR_ATOMIC_LOCK)
SWAP D1Re0,TXMASKI /* Really stop ints */
LOCK2 /* Gain all locks */
SET [A0.3+#UON],D1RtP /* Stop shared memory access too */
DCACHE [D1Ar1],A0.3 /* Flush Cache line */
GETD D0Re0,[D1Ar1] /* Get new state from memory or hit */
DCACHE [D1Ar1],A0.3 /* Flush Cache line */
GETD D0Re0,[D1Ar1] /* Get current state */
TST D0Re0,D0Ar2 /* Are we clear to send? */
ORZ D0Re0,D0Re0,D0Ar2 /* Yes: So set bits and */
SETDZ [D1Ar1],D0Re0 /* transmit new state */
SET [A0.3+#UOFF],D1RtP /* Allow shared memory access */
LOCK0 /* Release all locks */
MOV TXMASKI,D1Re0 /* Allow ints */
$LPollEnd:
XORNZ D0Re0,D0Re0,D0Re0 /* No: Generate zero result */
MOV PC,D1RtP /* Return (NZ indicates failure) */
.size ___TBIPoll,.-___TBIPoll
/*
* End of tbicore.S
*/
/*
* tbictx.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* Explicit state save and restore routines forming part of the thread binary
* interface for META processors
*/
.file "tbictx.S"
#include <asm/metag_regs.h>
#include <asm/tbx.h>
#ifdef METAC_1_0
/* Ax.4 is NOT saved in XAX3 */
#define A0_4
#else
/* Ax.4 is saved in XAX4 */
#define A0_4 A0.4,
#endif
/* Size of the TBICTX structure */
#define TBICTX_BYTES ((TBICTX_AX_REGS*8)+TBICTX_AX)
/*
* TBIRES __TBINestInts( TBIRES State, void *pExt, int NoNestMask )
*/
.text
.balign 4
.global ___TBINestInts
.type ___TBINestInts,function
___TBINestInts:
XOR D0Ar4,D0Ar4,#-1 /* D0Ar4 = ~TrigBit */
AND D0Ar4,D0Ar4,#0xFFFF /* D0Ar4 &= 0xFFFF */
MOV D0Ar6,TXMASKI /* BGNDHALT currently enabled? */
TSTT D0Ar2,#TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XCBF_BIT
AND D0Ar4,D0Ar2,D0Ar4 /* D0Ar4 = Ints to allow */
XOR D0Ar2,D0Ar2,D0Ar4 /* Less Ints in TrigMask */
BNZ ___TBINestInts2 /* Jump if ctx save required! */
TSTT D0Ar2,#TBICTX_CBUF_BIT+TBICTX_CBRP_BIT /* Is catch state dirty? */
OR D0Ar4,D0Ar4,D0Ar6 /* Or in TXMASKI BGNDHALT if set */
TSTNZ D0Ar4,D0Ar4 /* Yes: AND triggers enabled */
MOV D0Re0,D0Ar2 /* Update State argument */
MOV D1Re0,D1Ar1 /* with less Ints in TrigMask */
MOVZ TXMASKI,D0Ar4 /* Early return: Enable Ints */
MOVZ PC,D1RtP /* Early return */
.size ___TBINestInts,.-___TBINestInts
/*
* Drop thru into sub-function-
*/
.global ___TBINestInts2
.type ___TBINestInts2,function
___TBINestInts2:
MOV D0FrT,A0FrP /* Full entry sequence so we */
ADD A0FrP,A0StP,#0 /* can make sub-calls */
MSETL [A0StP],D0FrT,D0.5,D0.6 /* and preserve our result */
ORT D0Ar2,D0Ar2,#TBICTX_XCBF_BIT /* Add in XCBF save request */
MOV D0.5,D0Ar2 /* Save State in DX.5 */
MOV D1.5,D1Ar1
OR D0.6,D0Ar4,D0Ar6 /* Save TrigMask in D0.6 */
MOVT D1RtP,#HI(___TBICtxSave) /* Save catch buffer */
CALL D1RtP,#LO(___TBICtxSave)
MOV TXMASKI,D0.6 /* Allow Ints */
MOV D0Re0,D0.5 /* Return State */
MOV D1Re0,D1.5
MGETL D0FrT,D0.5,D0.6,[A0FrP] /* Full exit sequence */
SUB A0StP,A0FrP,#(8*3)
MOV A0FrP,D0FrT
MOV PC,D1RtP
.size ___TBINestInts2,.-___TBINestInts2
/*
* void *__TBICtxSave( TBIRES State, void *pExt )
*
* D0Ar2 contains TBICTX_*_BIT values that control what
* extended data is to be saved beyond the end of D1Ar1.
* These bits must be ored into the SaveMask of this structure.
*
* Virtually all possible scratch registers are used.
*
* The D1Ar1 parameter is only used as the basis for saving
* CBUF state.
*/
/*
* If TBICTX_XEXT_BIT is specified in State. then State.pCtx->Ext is
* utilised to save the base address of the context save area and
* the extended states saved. The XEXT flag then indicates that the
* original state of the A0.2 and A1.2 registers from TBICTX.Ext.AX2
* are stored as the first part of the extended state structure.
*/
.balign 4
.global ___TBICtxSave
.type ___TBICtxSave,function
___TBICtxSave:
GETD D0Re0,[D1Ar1+#TBICTX_SaveMask-2] /* Get SaveMask */
TSTT D0Ar2,#TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XEXT_BIT
/* Just XCBF to save? */
MOV A0.2,D1Ar3 /* Save pointer into A0.2 */
MOV A1.2,D1RtP /* Free off D0FrT:D1RtP pair */
BZ $LCtxSaveCBUF /* Yes: Only XCBF may be saved */
TSTT D0Ar2,#TBICTX_XEXT_BIT /* Extended base-state model? */
BZ $LCtxSaveXDX8
GETL D0Ar6,D1Ar5,[D1Ar1+#TBICTX_Ext_AX2] /* Get A0.2, A1.2 state */
MOV D0Ar4,D0Ar2 /* Extract Ctx.SaveFlags value */
ANDMT D0Ar4,D0Ar4,#TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XEXT_BIT
SETD [D1Ar1+#TBICTX_Ext_Ctx_pExt],A0.2
SETD [D1Ar1+#TBICTX_Ext_Ctx_SaveMask-2],D0Ar4
SETL [A0.2++],D0Ar6,D1Ar5 /* Save A0.2, A1.2 state */
$LCtxSaveXDX8:
TSTT D0Ar2,#TBICTX_XDX8_BIT /* Save extended DX regs? */
BZ $LCtxSaveXAXX
/*
* Save 8 extra DX registers
*/
MSETL [A0.2],D0.8,D0.9,D0.10,D0.11,D0.12,D0.13,D0.14,D0.15
$LCtxSaveXAXX:
TSTT D0Ar2,#TBICTX_XAXX_BIT /* Save extended AX regs? */
SWAP D0Re0,A0.2 /* pDst into D0Re0 */
BZ $LCtxSaveXHL2
/*
* Save 4 extra AX registers
*/
MSETL [D0Re0], A0_4 A0.5,A0.6,A0.7 /* Save 8*3 bytes */
$LCtxSaveXHL2:
TSTT D0Ar2,#TBICTX_XHL2_BIT /* Save hardware-loop regs? */
SWAP D0Re0,A0.2 /* pDst back into A0.2 */
MOV D0Ar6,TXL1START
MOV D1Ar5,TXL2START
BZ $LCtxSaveXTDP
/*
* Save hardware loop registers
*/
SETL [A0.2++],D0Ar6,D1Ar5 /* Save 8*1 bytes */
MOV D0Ar6,TXL1END
MOV D1Ar5,TXL2END
MOV D0FrT,TXL1COUNT
MOV D1RtP,TXL2COUNT
MSETL [A0.2],D0Ar6,D0FrT /* Save 8*2 bytes */
/*
* Clear loop counters to disable any current loops
*/
XOR TXL1COUNT,D0FrT,D0FrT
XOR TXL2COUNT,D1RtP,D1RtP
$LCtxSaveXTDP:
TSTT D0Ar2,#TBICTX_XTDP_BIT /* Save per-thread DSP regs? */
BZ $LCtxSaveCBUF
/*
* Save per-thread DSP registers; ACC.0, PR.0, PI.1-3 (PI.0 is zero)
*/
#ifndef CTX_NO_DSP
D SETL [A0.2++],AC0.0,AC1.0 /* Save ACx.0 lower 32-bits */
DH SETL [A0.2++],AC0.0,AC1.0 /* Save ACx.0 upper 32-bits */
D SETL [A0.2++],D0AR.0,D1AR.0 /* Save DSP RAM registers */
D SETL [A0.2++],D0AR.1,D1AR.1
D SETL [A0.2++],D0AW.0,D1AW.0
D SETL [A0.2++],D0AW.1,D1AW.1
D SETL [A0.2++],D0BR.0,D1BR.0
D SETL [A0.2++],D0BR.1,D1BR.1
D SETL [A0.2++],D0BW.0,D1BW.0
D SETL [A0.2++],D0BW.1,D1BW.1
D SETL [A0.2++],D0ARI.0,D1ARI.0
D SETL [A0.2++],D0ARI.1,D1ARI.1
D SETL [A0.2++],D0AWI.0,D1AWI.0
D SETL [A0.2++],D0AWI.1,D1AWI.1
D SETL [A0.2++],D0BRI.0,D1BRI.0
D SETL [A0.2++],D0BRI.1,D1BRI.1
D SETL [A0.2++],D0BWI.0,D1BWI.0
D SETL [A0.2++],D0BWI.1,D1BWI.1
D SETD [A0.2++],T0
D SETD [A0.2++],T1
D SETD [A0.2++],T2
D SETD [A0.2++],T3
D SETD [A0.2++],T4
D SETD [A0.2++],T5
D SETD [A0.2++],T6
D SETD [A0.2++],T7
D SETD [A0.2++],T8
D SETD [A0.2++],T9
D SETD [A0.2++],TA
D SETD [A0.2++],TB
D SETD [A0.2++],TC
D SETD [A0.2++],TD
D SETD [A0.2++],TE
D SETD [A0.2++],TF
#else
ADD A0.2,A0.2,#(8*18+4*16)
#endif
MOV D0Ar6,TXMRSIZE
MOV D1Ar5,TXDRSIZE
SETL [A0.2++],D0Ar6,D1Ar5 /* Save 8*1 bytes */
$LCtxSaveCBUF:
#ifdef TBI_1_3
MOV D0Ar4,D0Re0 /* Copy Ctx Flags */
ANDT D0Ar4,D0Ar4,#TBICTX_XCBF_BIT /* mask XCBF if already set */
XOR D0Ar4,D0Ar4,#-1
AND D0Ar2,D0Ar2,D0Ar4 /* remove XCBF if already set */
#endif
TSTT D0Ar2,#TBICTX_XCBF_BIT /* Want to save CBUF? */
ANDT D0Ar2,D0Ar2,#TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XEXT_BIT
OR D0Ar2,D0Ar2,D0Re0 /* Generate new SaveMask */
SETD [D1Ar1+#TBICTX_SaveMask-2],D0Ar2/* Add in bits saved to TBICTX */
MOV D0Re0,A0.2 /* Return end of save area */
MOV D0Ar4,TXDIVTIME /* Get TXDIVTIME */
MOVZ PC,A1.2 /* No: Early return */
TSTT D0Ar2,#TBICTX_CBUF_BIT+TBICTX_CBRP_BIT /* Need to save CBUF? */
MOVZ PC,A1.2 /* No: Early return */
ORT D0Ar2,D0Ar2,#TBICTX_XCBF_BIT
SETD [D1Ar1+#TBICTX_SaveMask-2],D0Ar2/* Add in XCBF bit to TBICTX */
ADD A0.2,D1Ar1,#TBICTX_BYTES /* Dump CBUF state after TBICTX */
/*
* Save CBUF
*/
SETD [A0.2+# 0],TXCATCH0 /* Restore TXCATCHn */
SETD [A0.2+# 4],TXCATCH1
TSTT D0Ar2,#TBICTX_CBRP_BIT /* ... RDDIRTY was/is set */
SETD [A0.2+# 8],TXCATCH2
SETD [A0.2+#12],TXCATCH3
BZ $LCtxSaveComplete
SETL [A0.2+#(2*8)],RD /* Save read pipeline */
SETL [A0.2+#(3*8)],RD /* Save read pipeline */
SETL [A0.2+#(4*8)],RD /* Save read pipeline */
SETL [A0.2+#(5*8)],RD /* Save read pipeline */
SETL [A0.2+#(6*8)],RD /* Save read pipeline */
SETL [A0.2+#(7*8)],RD /* Save read pipeline */
AND TXDIVTIME,D0Ar4,#TXDIVTIME_DIV_BITS /* Clear RPDIRTY */
$LCtxSaveComplete:
MOV PC,A1.2 /* Return */
.size ___TBICtxSave,.-___TBICtxSave
/*
* void *__TBICtxRestore( TBIRES State, void *pExt )
*
* D0Ar2 contains TBICTX_*_BIT values that control what
* extended data is to be recovered from D1Ar3 (pExt).
*
* Virtually all possible scratch registers are used.
*/
/*
* If TBICTX_XEXT_BIT is specified in State. Then the saved state of
* the orginal A0.2 and A1.2 is restored from pExt and the XEXT
* related flags are removed from State.pCtx->SaveMask.
*
*/
.balign 4
.global ___TBICtxRestore
.type ___TBICtxRestore,function
___TBICtxRestore:
GETD D0Ar6,[D1Ar1+#TBICTX_CurrMODE] /* Get TXMODE Value */
ANDST D0Ar2,D0Ar2,#TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XEXT_BIT
MOV D1Re0,D0Ar2 /* Keep flags in D1Re0 */
MOV D0Re0,D1Ar3 /* D1Ar3 is default result */
MOVZ PC,D1RtP /* Early return, nothing to do */
ANDT D0Ar6,D0Ar6,#0xE000 /* Top bits of TXMODE required */
MOV A0.3,D0Ar6 /* Save TXMODE for later */
TSTT D1Re0,#TBICTX_XEXT_BIT /* Check for XEXT bit */
BZ $LCtxRestXDX8
GETD D0Ar4,[D1Ar1+#TBICTX_SaveMask-2]/* Get current SaveMask */
GETL D0Ar6,D1Ar5,[D0Re0++] /* Restore A0.2, A1.2 state */
ANDMT D0Ar4,D0Ar4,#(0xFFFF-(TBICTX_XDX8_BIT+TBICTX_XAXX_BIT+TBICTX_XHL2_BIT+TBICTX_XTDP_BIT+TBICTX_XEXT_BIT))
SETD [D1Ar1+#TBICTX_SaveMask-2],D0Ar4/* New SaveMask */
#ifdef METAC_1_0
SETD [D1Ar1+#TBICTX_Ext_AX2_U0],D0Ar6
MOV D0Ar6,D1Ar1
SETD [D0Ar6+#TBICTX_Ext_AX2_U1],D1Ar5
#else
SETL [D1Ar1+#TBICTX_Ext_AX2],D0Ar6,D1Ar5
#endif
$LCtxRestXDX8:
TSTT D1Re0,#TBICTX_XDX8_BIT /* Get extended DX regs? */
MOV A1.2,D1RtP /* Free off D1RtP register */
BZ $LCtxRestXAXX
/*
* Restore 8 extra DX registers
*/
MGETL D0.8,D0.9,D0.10,D0.11,D0.12,D0.13,D0.14,D0.15,[D0Re0]
$LCtxRestXAXX:
TSTT D1Re0,#TBICTX_XAXX_BIT /* Get extended AX regs? */
BZ $LCtxRestXHL2
/*
* Restore 3 extra AX registers
*/
MGETL A0_4 A0.5,A0.6,A0.7,[D0Re0] /* Get 8*3 bytes */
$LCtxRestXHL2:
TSTT D1Re0,#TBICTX_XHL2_BIT /* Get hardware-loop regs? */
BZ $LCtxRestXTDP
/*
* Get hardware loop registers
*/
MGETL D0Ar6,D0Ar4,D0Ar2,[D0Re0] /* Get 8*3 bytes */
MOV TXL1START,D0Ar6
MOV TXL2START,D1Ar5
MOV TXL1END,D0Ar4
MOV TXL2END,D1Ar3
MOV TXL1COUNT,D0Ar2
MOV TXL2COUNT,D1Ar1
$LCtxRestXTDP:
TSTT D1Re0,#TBICTX_XTDP_BIT /* Get per-thread DSP regs? */
MOVZ PC,A1.2 /* No: Early return */
/*
* Get per-thread DSP registers; ACC.0, PR.0, PI.1-3 (PI.0 is zero)
*/
MOV A0.2,D0Re0
GETL D0Ar6,D1Ar5,[D0Re0++#((16*4)+(18*8))]
#ifndef CTX_NO_DSP
D GETL AC0.0,AC1.0,[A0.2++] /* Restore ACx.0 lower 32-bits */
DH GETL AC0.0,AC1.0,[A0.2++] /* Restore ACx.0 upper 32-bits */
#else
ADD A0.2,A0.2,#(2*8)
#endif
ADD D0Re0,D0Re0,#(2*4)
MOV TXMODE,A0.3 /* Some TXMODE bits needed */
MOV TXMRSIZE,D0Ar6
MOV TXDRSIZE,D1Ar5
#ifndef CTX_NO_DSP
D GETL D0AR.0,D1AR.0,[A0.2++] /* Restore DSP RAM registers */
D GETL D0AR.1,D1AR.1,[A0.2++]
D GETL D0AW.0,D1AW.0,[A0.2++]
D GETL D0AW.1,D1AW.1,[A0.2++]
D GETL D0BR.0,D1BR.0,[A0.2++]
D GETL D0BR.1,D1BR.1,[A0.2++]
D GETL D0BW.0,D1BW.0,[A0.2++]
D GETL D0BW.1,D1BW.1,[A0.2++]
#else
ADD A0.2,A0.2,#(8*8)
#endif
MOV TXMODE,#0 /* Restore TXMODE */
#ifndef CTX_NO_DSP
D GETL D0ARI.0,D1ARI.0,[A0.2++]
D GETL D0ARI.1,D1ARI.1,[A0.2++]
D GETL D0AWI.0,D1AWI.0,[A0.2++]
D GETL D0AWI.1,D1AWI.1,[A0.2++]
D GETL D0BRI.0,D1BRI.0,[A0.2++]
D GETL D0BRI.1,D1BRI.1,[A0.2++]
D GETL D0BWI.0,D1BWI.0,[A0.2++]
D GETL D0BWI.1,D1BWI.1,[A0.2++]
D GETD T0,[A0.2++]
D GETD T1,[A0.2++]
D GETD T2,[A0.2++]
D GETD T3,[A0.2++]
D GETD T4,[A0.2++]
D GETD T5,[A0.2++]
D GETD T6,[A0.2++]
D GETD T7,[A0.2++]
D GETD T8,[A0.2++]
D GETD T9,[A0.2++]
D GETD TA,[A0.2++]
D GETD TB,[A0.2++]
D GETD TC,[A0.2++]
D GETD TD,[A0.2++]
D GETD TE,[A0.2++]
D GETD TF,[A0.2++]
#else
ADD A0.2,A0.2,#(8*8+4*16)
#endif
MOV PC,A1.2 /* Return */
.size ___TBICtxRestore,.-___TBICtxRestore
/*
* End of tbictx.S
*/
/*
* tbictxfpu.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.
*
* Explicit state save and restore routines forming part of the thread binary
* interface for META processors
*/
.file "tbifpuctx.S"
#include <asm/metag_regs.h>
#include <asm/tbx.h>
#ifdef TBI_1_4
/*
* void *__TBICtxFPUSave( TBIRES State, void *pExt )
*
* D0Ar2 contains TBICTX_*_BIT values that control what
* extended data is to be saved.
* These bits must be ored into the SaveMask of this structure.
*
* Virtually all possible scratch registers are used.
*/
.text
.balign 4
.global ___TBICtxFPUSave
.type ___TBICtxFPUSave,function
___TBICtxFPUSave:
/* D1Ar1:D0Ar2 - State
* D1Ar3 - pExt
* D0Ar4 - Value of METAC_CORE_ID
* D1Ar5 - Scratch
* D0Ar6 - Scratch
*/
/* If the FPAC bit isnt set then there is nothing to do */
TSTT D0Ar2,#TBICTX_FPAC_BIT
MOVZ PC, D1RtP
/* Obtain the Core config */
MOVT D0Ar4, #HI(METAC_CORE_ID)
ADD D0Ar4, D0Ar4, #LO(METAC_CORE_ID)
GETD D0Ar4, [D0Ar4]
/* Detect FX.8 - FX.15 and add to core config */
MOV D0Ar6, TXENABLE
AND D0Ar6, D0Ar6, #(TXENABLE_CLASSALT_FPUR8 << TXENABLE_CLASS_S)
AND D0Ar4, D0Ar4, #LO(0x0000FFFF)
ORT D0Ar4, D0Ar4, #HI(TBICTX_CFGFPU_FX16_BIT)
XOR D0Ar4, D0Ar4, D0Ar6
/* Save the relevant bits to the buffer */
SETD [D1Ar3++], D0Ar4
/* Save the relevant bits of TXDEFR (Assumes TXDEFR is coherent) ... */
MOV D0Ar6, TXDEFR
LSR D0Re0, D0Ar6, #8
AND D0Re0, D0Re0, #LO(TXDEFR_FPE_FE_BITS>>8)
AND D0Ar6, D0Ar6, #LO(TXDEFR_FPE_ICTRL_BITS)
OR D0Re0, D0Re0, D0Ar6
/* ... along with relevant bits of TXMODE to buffer */
MOV D0Ar6, TXMODE
ANDT D0Ar6, D0Ar6, #HI(TXMODE_FPURMODE_BITS)
ORT D0Ar6, D0Ar6, #HI(TXMODE_FPURMODEWRITE_BIT)
OR D0Ar6, D0Ar6, D0Re0
SETD [D1Ar3++], D0Ar6
GETD D0Ar6,[D1Ar1+#TBICTX_SaveMask-2] /* Get the current SaveMask */
/* D0Ar6 - pCtx->SaveMask */
TSTT D0Ar4, #HI(TBICTX_CFGFPU_FX16_BIT) /* Perform test here for extended FPU registers
* to avoid stalls
*/
/* Save the standard FPU registers */
F MSETL [D1Ar3++], FX.0, FX.2, FX.4, FX.6
/* Save the extended FPU registers if they are present */
BZ $Lskip_save_fx8_fx16
F MSETL [D1Ar3++], FX.8, FX.10, FX.12, FX.14
$Lskip_save_fx8_fx16:
/* Save the FPU Accumulator if it is present */
TST D0Ar4, #METAC_COREID_NOFPACC_BIT
BNZ $Lskip_save_fpacc
F SETL [D1Ar3++], ACF.0
F SETL [D1Ar3++], ACF.1
F SETL [D1Ar3++], ACF.2
$Lskip_save_fpacc:
/* Update pCtx->SaveMask */
ANDT D0Ar2, D0Ar2, #TBICTX_FPAC_BIT
OR D0Ar6, D0Ar6, D0Ar2
SETD [D1Ar1+#TBICTX_SaveMask-2],D0Ar6/* Add in XCBF bit to TBICTX */
MOV D0Re0, D1Ar3 /* Return end of save area */
MOV PC, D1RtP
.size ___TBICtxFPUSave,.-___TBICtxFPUSave
/*
* void *__TBICtxFPURestore( TBIRES State, void *pExt )
*
* D0Ar2 contains TBICTX_*_BIT values that control what
* extended data is to be recovered from D1Ar3 (pExt).
*
* Virtually all possible scratch registers are used.
*/
/*
* If TBICTX_XEXT_BIT is specified in State. Then the saved state of
* the orginal A0.2 and A1.2 is restored from pExt and the XEXT
* related flags are removed from State.pCtx->SaveMask.
*
*/
.balign 4
.global ___TBICtxFPURestore
.type ___TBICtxFPURestore,function
___TBICtxFPURestore:
/* D1Ar1:D0Ar2 - State
* D1Ar3 - pExt
* D0Ar4 - Value of METAC_CORE_ID
* D1Ar5 - Scratch
* D0Ar6 - Scratch
* D1Re0 - Scratch
*/
/* If the FPAC bit isnt set then there is nothing to do */
TSTT D0Ar2,#TBICTX_FPAC_BIT
MOVZ PC, D1RtP
/* Obtain the relevant bits of the Core config */
GETD D0Ar4, [D1Ar3++]
/* Restore FPU related parts of TXDEFR. Assumes TXDEFR is coherent */
GETD D1Ar5, [D1Ar3++]
MOV D0Ar6, D1Ar5
LSL D1Re0, D1Ar5, #8
ANDT D1Re0, D1Re0, #HI(TXDEFR_FPE_FE_BITS|TXDEFR_FPE_ICTRL_BITS)
AND D1Ar5, D1Ar5, #LO(TXDEFR_FPE_FE_BITS|TXDEFR_FPE_ICTRL_BITS)
OR D1Re0, D1Re0, D1Ar5
MOV D1Ar5, TXDEFR
ANDMT D1Ar5, D1Ar5, #HI(~(TXDEFR_FPE_FE_BITS|TXDEFR_FPE_ICTRL_BITS))
ANDMB D1Ar5, D1Ar5, #LO(~(TXDEFR_FPE_FE_BITS|TXDEFR_FPE_ICTRL_BITS))
OR D1Re0, D1Re0, D1Ar5
MOV TXDEFR, D1Re0
/* Restore relevant bits of TXMODE */
MOV D1Ar5, TXMODE
ANDMT D1Ar5, D1Ar5, #HI(~TXMODE_FPURMODE_BITS)
ANDT D0Ar6, D0Ar6, #HI(TXMODE_FPURMODE_BITS|TXMODE_FPURMODEWRITE_BIT)
OR D0Ar6, D0Ar6, D1Ar5
MOV TXMODE, D0Ar6
TSTT D0Ar4, #HI(TBICTX_CFGFPU_FX16_BIT) /* Perform test here for extended FPU registers
* to avoid stalls
*/
/* Save the standard FPU registers */
F MGETL FX.0, FX.2, FX.4, FX.6, [D1Ar3++]
/* Save the extended FPU registers if they are present */
BZ $Lskip_restore_fx8_fx16
F MGETL FX.8, FX.10, FX.12, FX.14, [D1Ar3++]
$Lskip_restore_fx8_fx16:
/* Save the FPU Accumulator if it is present */
TST D0Ar4, #METAC_COREID_NOFPACC_BIT
BNZ $Lskip_restore_fpacc
F GETL ACF.0, [D1Ar3++]
F GETL ACF.1, [D1Ar3++]
F GETL ACF.2, [D1Ar3++]
$Lskip_restore_fpacc:
MOV D0Re0, D1Ar3 /* Return end of save area */
MOV PC, D1RtP
.size ___TBICtxFPURestore,.-___TBICtxFPURestore
#endif /* TBI_1_4 */
/*
* End of tbictx.S
*/
/*
* 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
*/
/*
* tbidspram.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.
*
* Explicit state save and restore routines forming part of the thread binary
* interface for META processors
*/
.file "tbidspram.S"
/* These aren't generally useful to a user so for now, they arent publically available */
#define _TBIECH_DSPRAM_DUA_S 8
#define _TBIECH_DSPRAM_DUA_BITS 0x7f00
#define _TBIECH_DSPRAM_DUB_S 0
#define _TBIECH_DSPRAM_DUB_BITS 0x007f
/*
* void *__TBIDspramSaveA( short DspramSizes, void *pExt )
*/
.text
.balign 4
.global ___TBIDspramSaveA
.type ___TBIDspramSaveA,function
___TBIDspramSaveA:
SETL [A0StP++], D0.5, D1.5
MOV A0.3, D0Ar2
/* D1Ar1 - Dspram Sizes
* A0.4 - Pointer to buffer
*/
/* Save the specified amount of dspram DUA */
DL MOV D0AR.0, #0
LSR D1Ar1, D1Ar1, #_TBIECH_DSPRAM_DUA_S
AND D1Ar1, D1Ar1, #(_TBIECH_DSPRAM_DUA_BITS >> _TBIECH_DSPRAM_DUA_S)
SUB TXRPT, D1Ar1, #1
$L1:
DL MOV D0Re0, [D0AR.0++]
DL MOV D0Ar6, [D0AR.0++]
DL MOV D0Ar4, [D0AR.0++]
DL MOV D0.5, [D0AR.0++]
MSETL [A0.3++], D0Re0, D0Ar6, D0Ar4, D0.5
BR $L1
GETL D0.5, D1.5, [--A0StP]
MOV PC, D1RtP
.size ___TBIDspramSaveA,.-___TBIDspramSaveA
/*
* void *__TBIDspramSaveB( short DspramSizes, void *pExt )
*/
.balign 4
.global ___TBIDspramSaveB
.type ___TBIDspramSaveB,function
___TBIDspramSaveB:
SETL [A0StP++], D0.5, D1.5
MOV A0.3, D0Ar2
/* D1Ar1 - Dspram Sizes
* A0.3 - Pointer to buffer
*/
/* Save the specified amount of dspram DUA */
DL MOV D0BR.0, #0
LSR D1Ar1, D1Ar1, #_TBIECH_DSPRAM_DUB_S
AND D1Ar1, D1Ar1, #(_TBIECH_DSPRAM_DUB_BITS >> _TBIECH_DSPRAM_DUB_S)
SUB TXRPT, D1Ar1, #1
$L2:
DL MOV D0Re0, [D0BR.0++]
DL MOV D0Ar6, [D0BR.0++]
DL MOV D0Ar4, [D0BR.0++]
DL MOV D0.5, [D0BR.0++]
MSETL [A0.3++], D0Re0, D0Ar6, D0Ar4, D0.5
BR $L2
GETL D0.5, D1.5, [--A0StP]
MOV PC, D1RtP
.size ___TBIDspramSaveB,.-___TBIDspramSaveB
/*
* void *__TBIDspramRestoreA( short DspramSizes, void *pExt )
*/
.balign 4
.global ___TBIDspramRestoreA
.type ___TBIDspramRestoreA,function
___TBIDspramRestoreA:
SETL [A0StP++], D0.5, D1.5
MOV A0.3, D0Ar2
/* D1Ar1 - Dspram Sizes
* A0.3 - Pointer to buffer
*/
/* Restore the specified amount of dspram DUA */
DL MOV D0AW.0, #0
LSR D1Ar1, D1Ar1, #_TBIECH_DSPRAM_DUA_S
AND D1Ar1, D1Ar1, #(_TBIECH_DSPRAM_DUA_BITS >> _TBIECH_DSPRAM_DUA_S)
SUB TXRPT, D1Ar1, #1
$L3:
MGETL D0Re0, D0Ar6, D0Ar4, D0.5, [A0.3++]
DL MOV [D0AW.0++], D0Re0
DL MOV [D0AW.0++], D0Ar6
DL MOV [D0AW.0++], D0Ar4
DL MOV [D0AW.0++], D0.5
BR $L3
GETL D0.5, D1.5, [--A0StP]
MOV PC, D1RtP
.size ___TBIDspramRestoreA,.-___TBIDspramRestoreA
/*
* void *__TBIDspramRestoreB( short DspramSizes, void *pExt )
*/
.balign 4
.global ___TBIDspramRestoreB
.type ___TBIDspramRestoreB,function
___TBIDspramRestoreB:
SETL [A0StP++], D0.5, D1.5
MOV A0.3, D0Ar2
/* D1Ar1 - Dspram Sizes
* A0.3 - Pointer to buffer
*/
/* Restore the specified amount of dspram DUA */
DL MOV D0BW.0, #0
LSR D1Ar1, D1Ar1, #_TBIECH_DSPRAM_DUB_S
AND D1Ar1, D1Ar1, #(_TBIECH_DSPRAM_DUB_BITS >> _TBIECH_DSPRAM_DUB_S)
SUB TXRPT, D1Ar1, #1
$L4:
MGETL D0Re0, D0Ar6, D0Ar4, D0.5, [A0.3++]
DL MOV [D0BW.0++], D0Re0
DL MOV [D0BW.0++], D0Ar6
DL MOV [D0BW.0++], D0Ar4
DL MOV [D0BW.0++], D0.5
BR $L4
GETL D0.5, D1.5, [--A0StP]
MOV PC, D1RtP
.size ___TBIDspramRestoreB,.-___TBIDspramRestoreB
/*
* End of tbidspram.S
*/
/*
* tbilogf.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* Defines __TBILogF trap code for debugging messages and __TBICont for debug
* assert to be implemented on.
*/
.file "tbilogf.S"
/*
* Perform console printf using external debugger or host support
*/
.text
.balign 4
.global ___TBILogF
.type ___TBILogF,function
___TBILogF:
MSETL [A0StP],D0Ar6,D0Ar4,D0Ar2
SWITCH #0xC10020
MOV D0Re0,#0
SUB A0StP,A0StP,#24
MOV PC,D1RtP
.size ___TBILogF,.-___TBILogF
/*
* Perform wait for continue under control of the debugger
*/
.text
.balign 4
.global ___TBICont
.type ___TBICont,function
___TBICont:
MOV D0Ar6,#1
MSETL [A0StP],D0Ar6,D0Ar4,D0Ar2
SWITCH #0xC30006 /* Returns if we are to continue */
SUB A0StP,A0StP,#(8*3)
MOV PC,D1RtP /* Return */
.size ___TBICont,.-___TBICont
/*
* End of tbilogf.S
*/
/*
* tbipcx.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* Asyncronous trigger handling including exceptions
*/
.file "tbipcx.S"
#include <asm/metag_regs.h>
#include <asm/tbx.h>
/* BEGIN HACK */
/* define these for now while doing inital conversion to GAS
will fix properly later */
/* Signal identifiers always have the TBID_SIGNAL_BIT set and contain the
following related bit-fields */
#define TBID_SIGNUM_S 2
/* END HACK */
#ifdef METAC_1_0
/* Ax.4 is saved in TBICTX */
#define A0_4 ,A0.4
#else
/* Ax.4 is NOT saved in TBICTX */
#define A0_4
#endif
/* Size of the TBICTX structure */
#define TBICTX_BYTES ((TBICTX_AX_REGS*8)+TBICTX_AX)
#ifdef METAC_1_1
#ifndef BOOTROM
#ifndef SPECIAL_BUILD
/* Jump straight into the boot ROM version of this code */
#define CODE_USES_BOOTROM
#endif
#endif
#endif
/* Define space needed for CATCH buffer state in traditional units */
#define CATCH_ENTRIES 5
#define CATCH_ENTRY_BYTES 16
#ifndef CODE_USES_BOOTROM
#define A0GblIStP A0.15 /* PTBICTX for current thread in PRIV system */
#define A1GblIGbP A1.15 /* Interrupt A1GbP value in PRIV system */
#endif
/*
* TBIRES __TBIASyncTrigger( TBIRES State )
*/
.text
.balign 4
.global ___TBIASyncTrigger
.type ___TBIASyncTrigger,function
___TBIASyncTrigger:
#ifdef CODE_USES_BOOTROM
MOVT D0Re0,#HI(LINCORE_BASE)
JUMP D0Re0,#0xA0
#else
MOV D0FrT,A0FrP /* Boing entry sequence */
ADD A0FrP,A0StP,#0
SETL [A0StP++],D0FrT,D1RtP
MOV D0Re0,PCX /* Check for repeat call */
MOVT D0FrT,#HI(___TBIBoingRTI+4)
ADD D0FrT,D0FrT,#LO(___TBIBoingRTI+4)
CMP D0Re0,D0FrT
BEQ ___TBIBoingExit /* Already set up - come out */
ADD D1Ar1,D1Ar1,#7 /* PRIV system stack here */
MOV A0.2,A0StP /* else push context here */
MOVS D0Re0,D0Ar2 /* Return in user mode? */
ANDMB D1Ar1,D1Ar1,#0xfff8 /* align priv stack to 64-bit */
MOV D1Re0,D1Ar1 /* and set result to arg */
MOVMI A0.2,D1Ar1 /* use priv stack if PRIV set */
/*
* Generate an initial TBICTX to return to our own current call context
*/
MOVT D1Ar5,#HI(___TBIBoingExit) /* Go here to return */
ADD D1Ar5,D1Ar5,#LO(___TBIBoingExit)
ADD A0.3,A0.2,#TBICTX_DX /* DX Save area */
ANDT D0Ar2,D0Ar2,#TBICTX_PRIV_BIT /* Extract PRIV bit */
MOVT D0Ar6,#TBICTX_SOFT_BIT /* Only soft thread state */
ADD D0Ar6,D0Ar6,D0Ar2 /* Add in PRIV bit if requested */
SETL [A0.2],D0Ar6,D1Ar5 /* Push header fields */
ADD D0FrT,A0.2,#TBICTX_AX /* Address AX save area */
MSETL [A0.3],D0Re0,D0Ar6,D0Ar4,D0Ar2,D0FrT,D0.5,D0.6,D0.7
MOV D0Ar6,#0
MOV D1Ar5,#0
SETL [A0.3++],D0Ar6,D1Ar5 /* Zero CT register states */
SETL [A0.3++],D0Ar6,D1Ar5
MSETL [D0FrT],A0StP,A0FrP,A0.2,A0.3 A0_4 /* Save AX regs */
MOV A0FrP,A0.2 /* Restore me! */
B ___TBIResume
.size ___TBIASyncTrigger,.-___TBIASyncTrigger
/*
* Optimised return to handler for META Core
*/
___TBIBoingRTH:
RTH /* Go to background level */
MOVT A0.2, #HI($Lpcx_target)
ADD A0.2,A0.2,#LO($Lpcx_target)
MOV PCX,A0.2 /* Setup PCX for interrupts */
MOV PC,D1Re0 /* Jump to handler */
/*
* This is where the code below needs to jump to wait for outermost interrupt
* event in a non-privilege mode system (single shared interrupt stack).
*/
___TBIBoingPCX:
MGETL A0StP,A0FrP,A0.2,A0.3 A0_4,[D1Re0] /* Restore AX regs */
MOV TXSTATUS,D0Re0 /* Restore flags */
GETL D0Re0,D1Re0,[D1Re0+#TBICTX_DX-TBICTX_BYTES]
___TBIBoingRTI:
RTI /* Wait for interrupt */
$Lpcx_target:
/*
* Save initial interrupt state on current stack
*/
SETL [A0StP+#TBICTX_DX],D0Re0,D1Re0 /* Save key registers */
ADD D1Re0,A0StP,#TBICTX_AX /* Address AX save area */
MOV D0Re0,TXSTATUS /* Read TXSTATUS into D0Re0 */
MOV TXSTATUS,#0 /* Clear TXSTATUS */
MSETL [D1Re0],A0StP,A0FrP,A0.2,A0.3 A0_4 /* Save AX critical regs */
/*
* Register state at this point is-
*
* D0Re0 - Old TXSTATUS with PRIV and CBUF bits set if appropriate
* A0StP - Is call stack frame and base of TBICTX being generated
* A1GbP - Is valid static access link
*/
___TBIBoing:
LOCK0 /* Make sure we have no locks! */
ADD A1.2,A0StP,#TBICTX_DX+(8*1) /* Address DX.1 save area */
MOV A0FrP,A0StP /* Setup frame pointer */
MSETL [A1.2],D0Ar6,D0Ar4,D0Ar2,D0FrT,D0.5,D0.6,D0.7
MOV D0Ar4,TXRPT /* Save critical CT regs */
MOV D1Ar3,TXBPOBITS
MOV D1Ar1,TXDIVTIME /* Calc catch buffer pSrc */
MOV D0Ar2,TXMODE
MOV TXMODE,#0 /* Clear TXMODE */
#ifdef TXDIVTIME_RPDIRTY_BIT
TSTT D1Ar1,#HI(TXDIVTIME_RPDIRTY_BIT)/* NZ = RPDIRTY */
MOVT D0Ar6,#TBICTX_CBRP_BIT
ORNZ D0Re0,D0Re0,D0Ar6 /* Set CBRP if RPDIRTY set */
#endif
MSETL [A1.2],D0Ar4,D0Ar2 /* Save CT regs state */
MOV D0Ar2,D0Re0 /* Copy TXSTATUS */
ANDMT D0Ar2,D0Ar2,#TBICTX_CBUF_BIT+TBICTX_CBRP_BIT
#ifdef TBI_1_4
MOVT D1Ar1,#TBICTX_FPAC_BIT /* Copy FPActive into FPAC */
TSTT D0Re0,#HI(TXSTATUS_FPACTIVE_BIT)
ORNZ D0Ar2,D0Ar2,D1Ar1
#endif
MOV D1Ar1,PCX /* Read CurrPC */
ORT D0Ar2,D0Ar2,#TBICTX_CRIT_BIT /* SaveMask + CRIT bit */
SETL [A0FrP+#TBICTX_Flags],D0Ar2,D1Ar1 /* Set pCtx header fields */
/*
* Completed context save, now we need to make a call to an interrupt handler
*
* D0Re0 - holds PRIV, WAIT, CBUF flags, HALT reason if appropriate
* A0FrP - interrupt stack frame and base of TBICTX being generated
* A0StP - same as A0FrP
*/
___TBIBoingWait:
/* Reserve space for TBICTX and CBUF */
ADD A0StP,A0StP,#TBICTX_BYTES+(CATCH_ENTRY_BYTES*CATCH_ENTRIES)
MOV D0Ar4,TXSTATI /* Read the Triggers data */
MOV D1Ar3,TXDIVTIME /* Read IRQEnc bits */
MOV D0Ar2,D0Re0 /* Copy PRIV and WAIT flags */
ANDT D0Ar2,D0Ar2,#TBICTX_PRIV_BIT+TBICTX_WAIT_BIT+TBICTX_CBUF_BIT
#ifdef TBI_1_4
MOVT D1Ar5,#TBICTX_FPAC_BIT /* Copy FPActive into FPAC */
TSTT D0Re0,#HI(TXSTATUS_FPACTIVE_BIT)
ORNZ D0Ar2,D0Ar2,D1Ar5
#endif
ANDT D1Ar3,D1Ar3,#HI(TXDIVTIME_IRQENC_BITS)
LSR D1Ar3,D1Ar3,#TXDIVTIME_IRQENC_S
AND TXSTATI,D0Ar4,#TXSTATI_BGNDHALT_BIT/* Ack any HALT seen */
ANDS D0Ar4,D0Ar4,#0xFFFF-TXSTATI_BGNDHALT_BIT /* Only seen HALT? */
ORT D0Ar2,D0Ar2,#TBICTX_CRIT_BIT /* Set CRIT */
#ifndef BOOTROM
MOVT A1LbP,#HI(___pTBIs)
ADD A1LbP,A1LbP,#LO(___pTBIs)
GETL D1Ar5,D0Ar6,[A1LbP] /* D0Ar6 = ___pTBIs[1] */
#else
/*
* For BOOTROM support ___pTBIs must be allocated at offset 0 vs A1GbP
*/
GETL D1Ar5,D0Ar6,[A1GbP] /* D0Ar6 = ___pTBIs[1] */
#endif
BZ ___TBIBoingHalt /* Yes: Service HALT */
/*
* Encode interrupt as signal vector, strip away same/lower TXMASKI bits
*/
MOV D1Ar1,#1 /* Generate mask for this bit */
MOV D0Re0,TXMASKI /* Get interrupt mask */
LSL TXSTATI,D1Ar1,D1Ar3 /* Acknowledge trigger */
AND TXMASKI,D0Re0,#TXSTATI_BGNDHALT_BIT /* Only allow HALTs */
OR D0Ar2,D0Ar2,D0Re0 /* Set TBIRES.Sig.TrigMask */
ADD D1Ar3,D1Ar3,#TBID_SIGNUM_TRT /* Offset into interrupt sigs */
LSL D0Re0,D1Ar3,#TBID_SIGNUM_S /* Generate offset from SigNum */
/*
* This is a key moment we are about to call the handler, register state is
* as follows-
*
* D0Re0 - Handler vector (SigNum<<TBID_SIGNUM_S)
* D0Ar2 - TXMASKI:TBICTX_CRIT_BIT with optional CBUF and PRIV bits
* D1Ar3 - SigNum
* D0Ar4 - State read from TXSTATI
* D1Ar5 - Inst for SWITCH trigger case only, otherwise undefined
* D0Ar6 - pTBI
*/
___TBIBoingVec:
ADD D0Re0,D0Re0,#TBI_fnSigs /* Offset into signal table */
GETD D1Re0,[D0Ar6+D0Re0] /* Get address for Handler */
/*
* Call handler at interrupt level, when it returns simply resume execution
* of state indicated by D1Re0.
*/
MOV D1Ar1,A0FrP /* Pass in pCtx */
CALLR D1RtP,___TBIBoingRTH /* Use RTH to invoke handler */
/*
* Perform critical state restore and execute background thread.
*
* A0FrP - is pointer to TBICTX structure to resume
* D0Re0 - contains additional TXMASKI triggers
*/
.text
.balign 4
#ifdef BOOTROM
.global ___TBIResume
#endif
___TBIResume:
/*
* New META IP method
*/
RTH /* Go to interrupt level */
MOV D0Ar4,TXMASKI /* Read TXMASKI */
OR TXMASKI,D0Ar4,D0Re0 /* -Write-Modify TXMASKI */
GETL D0Re0,D1Re0,[A0FrP+#TBICTX_Flags]/* Get Flags:SaveMask, CurrPC */
MOV A0StP,A0FrP /* Position stack pointer */
MOV D0Ar2,TXPOLLI /* Read pending triggers */
MOV PCX,D1Re0 /* Set resumption PC */
TST D0Ar2,#0xFFFF /* Any pending triggers? */
BNZ ___TBIBoingWait /* Yes: Go for triggers */
TSTT D0Re0,#TBICTX_WAIT_BIT /* Do we WAIT anyway? */
BNZ ___TBIBoingWait /* Yes: Go for triggers */
LSLS D1Ar5,D0Re0,#1 /* Test XCBF (MI) & PRIV (CS)? */
ADD D1Re0,A0FrP,#TBICTX_CurrRPT /* Address CT save area */
ADD A0StP,A0FrP,#TBICTX_DX+(8*1) /* Address DX.1 save area */
MGETL A0.2,A0.3,[D1Re0] /* Get CT reg states */
MOV D1Ar3,A1.3 /* Copy old TXDIVTIME */
BPL ___TBIResCrit /* No: Skip logic */
ADD D0Ar4,A0FrP,#TBICTX_BYTES /* Source is after TBICTX */
ANDST D1Ar3,D1Ar3,#HI(TXDIVTIME_RPMASK_BITS)/* !Z if RPDIRTY */
MGETL D0.5,D0.6,[D0Ar4] /* Read Catch state */
MOV TXCATCH0,D0.5 /* Restore TXCATCHn */
MOV TXCATCH1,D1.5
MOV TXCATCH2,D0.6
MOV TXCATCH3,D1.6
BZ ___TBIResCrit
MOV D0Ar2,#(1*8)
LSRS D1Ar3,D1Ar3,#TXDIVTIME_RPMASK_S+1 /* 2nd RPMASK bit -> bit 0 */
ADD RA,D0Ar4,#(0*8) /* Re-read read pipeline */
ADDNZ RA,D0Ar4,D0Ar2 /* If Bit 0 set issue RA */
LSRS D1Ar3,D1Ar3,#2 /* Bit 1 -> C, Bit 2 -> Bit 0 */
ADD D0Ar2,D0Ar2,#8
ADDCS RA,D0Ar4,D0Ar2 /* If C issue RA */
ADD D0Ar2,D0Ar2,#8
ADDNZ RA,D0Ar4,D0Ar2 /* If Bit 0 set issue RA */
LSRS D1Ar3,D1Ar3,#2 /* Bit 1 -> C, Bit 2 -> Bit 0 */
ADD D0Ar2,D0Ar2,#8
ADDCS RA,D0Ar4,D0Ar2 /* If C issue RA */
ADD D0Ar2,D0Ar2,#8
ADDNZ RA,D0Ar4,D0Ar2 /* If Bit 0 set issue RA */
MOV TXDIVTIME,A1.3 /* Set RPDIRTY again */
___TBIResCrit:
LSLS D1Ar5,D0Re0,#1 /* Test XCBF (MI) & PRIV (CS)? */
#ifdef TBI_1_4
ANDT D1Ar5,D1Ar5,#(TBICTX_FPAC_BIT*2)
LSL D0Ar6,D1Ar5,#3 /* Convert FPAC into FPACTIVE */
#endif
ANDMT D0Re0,D0Re0,#TBICTX_CBUF_BIT /* Keep CBUF bit from SaveMask */
#ifdef TBI_1_4
OR D0Re0,D0Re0,D0Ar6 /* Combine FPACTIVE with others */
#endif
MGETL D0Ar6,D0Ar4,D0Ar2,D0FrT,D0.5,D0.6,D0.7,[A0StP] /* Restore DX */
MOV TXRPT,A0.2 /* Restore CT regs */
MOV TXBPOBITS,A1.2
MOV TXMODE,A0.3
BCC ___TBIBoingPCX /* Do non-PRIV wait! */
MOV A1GblIGbP,A1GbP /* Save A1GbP too */
MGETL A0StP,A0FrP,A0.2,A0.3 A0_4,[D1Re0] /* Restore AX regs */
/*
* Wait for the first interrupt/exception trigger in a privilege mode system
* (interrupt stack area for current TASK to be pointed to by A0GblIStP
* or per_cpu__stack_save[hwthread_id]).
*/
MOV TXSTATUS,D0Re0 /* Restore flags */
MOV D0Re0,TXPRIVEXT /* Set TXPRIVEXT_TXTOGGLEI_BIT */
SUB D1Re0,D1Re0,#TBICTX_BYTES /* TBICTX is top of int stack */
#ifdef TBX_PERCPU_SP_SAVE
SWAP D1Ar3,A1GbP
MOV D1Ar3,TXENABLE /* Which thread are we? */
AND D1Ar3,D1Ar3,#TXENABLE_THREAD_BITS
LSR D1Ar3,D1Ar3,#TXENABLE_THREAD_S-2
ADDT D1Ar3,D1Ar3,#HI(_per_cpu__stack_save)
ADD D1Ar3,D1Ar3,#LO(_per_cpu__stack_save)
SETD [D1Ar3],D1Re0
SWAP D1Ar3,A1GbP
#else
MOV A0GblIStP, D1Re0
#endif
OR D0Re0,D0Re0,#TXPRIVEXT_TXTOGGLEI_BIT
MOV TXPRIVEXT,D0Re0 /* Cannot set TXPRIVEXT if !priv */
GETL D0Re0,D1Re0,[D1Re0+#TBICTX_DX]
RTI /* Wait for interrupt */
/*
* Save initial interrupt state on A0GblIStP, switch to A0GblIStP if
* BOOTROM code, save and switch to [A1GbP] otherwise.
*/
___TBIBoingPCXP:
#ifdef TBX_PERCPU_SP_SAVE
SWAP D1Ar3,A1GbP /* Get PRIV stack base */
MOV D1Ar3,TXENABLE /* Which thread are we? */
AND D1Ar3,D1Ar3,#TXENABLE_THREAD_BITS
LSR D1Ar3,D1Ar3,#TXENABLE_THREAD_S-2
ADDT D1Ar3,D1Ar3,#HI(_per_cpu__stack_save)
ADD D1Ar3,D1Ar3,#LO(_per_cpu__stack_save)
GETD D1Ar3,[D1Ar3]
#else
SWAP D1Ar3,A0GblIStP /* Get PRIV stack base */
#endif
SETL [D1Ar3+#TBICTX_DX],D0Re0,D1Re0 /* Save key registers */
MOV D0Re0,TXPRIVEXT /* Clear TXPRIVEXT_TXTOGGLEI_BIT */
ADD D1Re0,D1Ar3,#TBICTX_AX /* Address AX save area */
ANDMB D0Re0,D0Re0,#0xFFFF-TXPRIVEXT_TXTOGGLEI_BIT
MOV TXPRIVEXT,D0Re0 /* Cannot set TXPRIVEXT if !priv */
MOV D0Re0,TXSTATUS /* Read TXSTATUS into D0Re0 */
MOV TXSTATUS,#0 /* Clear TXSTATUS */
MSETL [D1Re0],A0StP,A0FrP,A0.2,A0.3 A0_4 /* Save AX critical regs */
MOV A0StP,D1Ar3 /* Switch stacks */
#ifdef TBX_PERCPU_SP_SAVE
MOV D1Ar3,A1GbP /* Get D1Ar2 back */
#else
MOV D1Ar3,A0GblIStP /* Get D1Ar2 back */
#endif
ORT D0Re0,D0Re0,#TBICTX_PRIV_BIT /* Add PRIV to TXSTATUS */
MOV A1GbP,A1GblIGbP /* Restore A1GbP */
B ___TBIBoing /* Enter common handler code */
/*
* At this point we know it's a background HALT case we are handling.
* The restored TXSTATUS always needs to have zero in the reason bits.
*/
___TBIBoingHalt:
MOV D0Ar4,TXMASKI /* Get interrupt mask */
ANDST D0Re0,D0Re0,#HI(TXSTATUS_MAJOR_HALT_BITS+TXSTATUS_MEM_FAULT_BITS)
AND TXMASKI,D0Ar4,#TXSTATI_BGNDHALT_BIT /* Only allow HALTs */
AND D0Ar4,D0Ar4,#0xFFFF-TXSTATI_BGNDHALT_BIT /* What ints are off? */
OR D0Ar2,D0Ar2,D0Ar4 /* Set TBIRES.Sig.TrigMask */
MOV D0Ar4,#TXSTATI_BGNDHALT_BIT /* This was the trigger state */
LSR D1Ar3,D0Re0,#TXSTATUS_MAJOR_HALT_S
MOV D0Re0,#TBID_SIGNUM_XXF<<TBID_SIGNUM_S
BNZ ___TBIBoingVec /* Jump to XXF exception handler */
/*
* Only the SWITCH cases are left, PCX must be valid
*/
#ifdef TBI_1_4
MOV D1Ar5,TXPRIVEXT
TST D1Ar5,#TXPRIVEXT_MINIMON_BIT
LSR D1Ar3,D1Ar1,#1 /* Shift needed for MINIM paths (fill stall) */
BZ $Lmeta /* If META only, skip */
TSTT D1Ar1,#HI(0x00800000)
ANDMT D1Ar3,D1Ar3,#HI(0x007FFFFF >> 1)/* Shifted mask for large MINIM */
ANDT D1Ar1,D1Ar1,#HI(0xFFE00000) /* Static mask for small MINIM */
BZ $Llarge_minim /* If large MINIM */
$Lsmall_minim:
TSTT D1Ar3,#HI(0x00100000 >> 1)
ANDMT D1Ar3,D1Ar3,#HI(0x001FFFFF >> 1)/* Correct shifted mask for large MINIM */
ADDZ D1Ar1,D1Ar1,D1Ar3 /* If META rgn, add twice to undo LSR #1 */
B $Lrecombine
$Llarge_minim:
ANDST D1Ar1,D1Ar1,#HI(0xFF800000) /* Correct static mask for small MINIM */
/* Z=0 (Cannot place code at NULL) */
$Lrecombine:
ADD D1Ar1,D1Ar1,D1Ar3 /* Combine static and shifted parts */
$Lmeta:
GETW D1Ar5,[D1Ar1++] /* META: lo-16, MINIM: lo-16 (all-16 if short) */
GETW D1Ar3,[D1Ar1] /* META: hi-16, MINIM: hi-16 (only if long) */
MOV D1Re0,D1Ar5
XOR D1Re0,D1Re0,#0x4000
LSLSNZ D1Re0,D1Re0,#(32-14) /* MINIM: If long C=0, if short C=1 */
LSLCC D1Ar3,D1Ar3,#16 /* META/MINIM long: Move hi-16 up */
LSLCS D1Ar3,D1Ar5,#16 /* MINIM short: Dup all-16 */
ADD D1Ar5,D1Ar5,D1Ar3 /* ALL: Combine both 16-bit parts */
#else
GETD D1Ar5,[D1Ar1] /* Read instruction for switch */
#endif
LSR D1Ar3,D1Ar5,#22 /* Convert into signal number */
AND D1Ar3,D1Ar3,#TBID_SIGNUM_SW3-TBID_SIGNUM_SW0
LSL D0Re0,D1Ar3,#TBID_SIGNUM_S /* Generate offset from SigNum */
B ___TBIBoingVec /* Jump to switch handler */
/*
* Exit from TBIASyncTrigger call
*/
___TBIBoingExit:
GETL D0FrT,D1RtP,[A0FrP++] /* Restore state from frame */
SUB A0StP,A0FrP,#8 /* Unwind stack */
MOV A0FrP,D0FrT /* Last memory read completes */
MOV PC,D1RtP /* Return to caller */
#endif /* ifdef CODE_USES_BOOTROM */
.size ___TBIResume,.-___TBIResume
#ifndef BOOTROM
/*
* void __TBIASyncResume( TBIRES State )
*/
.text
.balign 4
.global ___TBIASyncResume
.type ___TBIASyncResume,function
___TBIASyncResume:
/*
* Perform CRIT|SOFT state restore and execute background thread.
*/
MOV D1Ar3,D1Ar1 /* Restore this context */
MOV D0Re0,D0Ar2 /* Carry in additional triggers */
/* Reserve space for TBICTX */
ADD D1Ar3,D1Ar3,#TBICTX_BYTES+(CATCH_ENTRY_BYTES*CATCH_ENTRIES)
MOV A0StP,D1Ar3 /* Enter with protection of */
MOV A0FrP,D1Ar1 /* TBICTX on our stack */
#ifdef CODE_USES_BOOTROM
MOVT D1Ar1,#HI(LINCORE_BASE)
JUMP D1Ar1,#0xA4
#else
B ___TBIResume
#endif
.size ___TBIASyncResume,.-___TBIASyncResume
#endif /* ifndef BOOTROM */
/*
* End of tbipcx.S
*/
/*
* tbiroot.S
*
* Copyright (C) 2001, 2002, 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.
*
* Module that creates and via ___TBI function returns a TBI Root Block for
* interrupt and background processing on the current thread.
*/
.file "tbiroot.S"
#include <asm/metag_regs.h>
/*
* Get data structures and defines from the TBI C header
*/
#include <asm/tbx.h>
/* If signals need to be exchanged we must create a TBI Root Block */
.data
.balign 8
.global ___pTBIs
.type ___pTBIs,object
___pTBIs:
.long 0 /* Bgnd+Int root block ptrs */
.long 0
.size ___pTBIs,.-___pTBIs
/*
* Return ___pTBIs value specific to execution level with promotion/demotion
*
* Register Usage: D1Ar1 is Id, D0Re0 is the primary result
* D1Re0 is secondary result (___pTBIs for other exec level)
*/
.text
.balign 4
.global ___TBI
.type ___TBI,function
___TBI:
TSTT D1Ar1,#HI(TBID_ISTAT_BIT) /* Bgnd or Int level? */
MOVT A1LbP,#HI(___pTBIs)
ADD A1LbP,A1LbP,#LO(___pTBIs)
GETL D0Re0,D1Re0,[A1LbP] /* Base of root block table */
SWAPNZ D0Re0,D1Re0 /* Swap if asked */
MOV PC,D1RtP
.size ___TBI,.-___TBI
/*
* Return identifier of the current thread in TBI segment or signal format with
* secondary mask to indicate privilege and interrupt level of thread
*/
.text
.balign 4
.global ___TBIThrdPrivId
.type ___TBIThrdPrivId,function
___TBIThrdPrivId:
.global ___TBIThreadId
.type ___TBIThreadId,function
___TBIThreadId:
#ifndef METAC_0_1
MOV D1Re0,TXSTATUS /* Are we privileged or int? */
MOV D0Re0,TXENABLE /* Which thread are we? */
/* Disable privilege adaption for now */
ANDT D1Re0,D1Re0,#HI(TXSTATUS_ISTAT_BIT) /* +TXSTATUS_PSTAT_BIT) */
LSL D1Re0,D1Re0,#TBID_ISTAT_S-TXSTATUS_ISTAT_S
AND D0Re0,D0Re0,#TXENABLE_THREAD_BITS
LSL D0Re0,D0Re0,#TBID_THREAD_S-TXENABLE_THREAD_S
#else
/* Thread 0 only */
XOR D0Re0,D0Re0,D0Re0
XOR D1Re0,D1Re0,D1Re0
#endif
MOV PC,D1RtP /* Return */
.size ___TBIThrdPrivId,.-___TBIThrdPrivId
.size ___TBIThreadId,.-___TBIThreadId
/*
* End of tbiroot.S
*/
/*
* tbisoft.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* Support for soft threads and soft context switches
*/
.file "tbisoft.S"
#include <asm/tbx.h>
#ifdef METAC_1_0
/* Ax.4 is saved in TBICTX */
#define A0_4 ,A0.4
#define D0_5 ,D0.5
#else
/* Ax.4 is NOT saved in TBICTX */
#define A0_4
#define D0_5
#endif
/* Size of the TBICTX structure */
#define TBICTX_BYTES ((TBICTX_AX_REGS*8)+TBICTX_AX)
.text
.balign 4
.global ___TBISwitchTail
.type ___TBISwitchTail,function
___TBISwitchTail:
B $LSwitchTail
.size ___TBISwitchTail,.-___TBISwitchTail
/*
* TBIRES __TBIJumpX( TBIX64 ArgsA, PTBICTX *rpSaveCtx, int TrigsMask,
* void (*fnMain)(), void *pStack );
*
* This is a combination of __TBISwitch and __TBIJump with the context of
* the calling thread being saved in the rpSaveCtx location with a drop-thru
* effect into the __TBIJump logic. ArgsB passes via __TBIJump to the
* routine eventually invoked will reflect the rpSaveCtx value specified.
*/
.text
.balign 4
.global ___TBIJumpX
.type ___TBIJumpX,function
___TBIJumpX:
CMP D1RtP,#-1
B $LSwitchStart
.size ___TBIJumpX,.-___TBIJumpX
/*
* TBIRES __TBISwitch( TBIRES Switch, PTBICTX *rpSaveCtx )
*
* Software syncronous context switch between soft threads, save only the
* registers which are actually valid on call entry.
*
* A0FrP, D0RtP, D0.5, D0.6, D0.7 - Saved on stack
* A1GbP is global to all soft threads so not virtualised
* A0StP is then saved as the base of the TBICTX of the thread
*
*/
.text
.balign 4
.global ___TBISwitch
.type ___TBISwitch,function
___TBISwitch:
XORS D0Re0,D0Re0,D0Re0 /* Set ZERO flag */
$LSwitchStart:
MOV D0FrT,A0FrP /* Boing entry sequence */
ADD A0FrP,A0StP,#0
SETL [A0StP+#8++],D0FrT,D1RtP
/*
* Save current frame state - we save all regs because we don't want
* uninitialised crap in the TBICTX structure that the asyncronous resumption
* of a thread will restore.
*/
MOVT D1Re0,#HI($LSwitchExit) /* ASync resume point here */
ADD D1Re0,D1Re0,#LO($LSwitchExit)
SETD [D1Ar3],A0StP /* Record pCtx of this thread */
MOVT D0Re0,#TBICTX_SOFT_BIT /* Only soft thread state */
SETL [A0StP++],D0Re0,D1Re0 /* Push header fields */
ADD D0FrT,A0StP,#TBICTX_AX-TBICTX_DX /* Address AX save area */
MOV D0Re0,#0 /* Setup 0:0 result for ASync */
MOV D1Re0,#0 /* resume of the thread */
MSETL [A0StP],D0Re0,D0Ar6,D0Ar4,D0Ar2,D0FrT,D0.5,D0.6,D0.7
SETL [A0StP++],D0Re0,D1Re0 /* Zero CurrRPT, CurrBPOBITS, */
SETL [A0StP++],D0Re0,D1Re0 /* Zero CurrMODE, CurrDIVTIME */
ADD A0StP,A0StP,#(TBICTX_AX_REGS*8) /* Reserve AX save space */
MSETL [D0FrT],A0StP,A0FrP,A0.2,A0.3 A0_4 /* Save AX regs */
BNZ ___TBIJump
/*
* NextThread MUST be in TBICTX_SOFT_BIT state!
*/
$LSwitchTail:
MOV D0Re0,D0Ar2 /* Result from args */
MOV D1Re0,D1Ar1
ADD D1RtP,D1Ar1,#TBICTX_AX
MGETL A0StP,A0FrP,[D1RtP] /* Get frame values */
$LSwitchCmn:
ADD A0.2,D1Ar1,#TBICTX_DX+(8*5)
MGETL D0.5,D0.6,D0.7,[A0.2] /* Get caller-saved DX regs */
$LSwitchExit:
GETL D0FrT,D1RtP,[A0FrP++] /* Restore state from frame */
SUB A0StP,A0FrP,#8 /* Unwind stack */
MOV A0FrP,D0FrT /* Last memory read completes */
MOV PC,D1RtP /* Return to caller */
.size ___TBISwitch,.-___TBISwitch
/*
* void __TBISyncResume( TBIRES State, int TrigMask );
*
* This routine causes the TBICTX structure specified in State.Sig.pCtx to
* be restored. This implies that execution will not return to the caller.
* The State.Sig.TrigMask field will be ored into TXMASKI during the
* context switch such that any immediately occuring interrupts occur in
* the context of the newly specified task. The State.Sig.SaveMask parameter
* is ignored.
*/
.text
.balign 4
.global ___TBISyncResume
.type ___TBISyncResume,function
___TBISyncResume:
MOV D0Re0,D0Ar2 /* Result from args */
MOV D1Re0,D1Ar1
XOR D1Ar5,D1Ar5,D1Ar5 /* D1Ar5 = 0 */
ADD D1RtP,D1Ar1,#TBICTX_AX
SWAP D1Ar5,TXMASKI /* D1Ar5 <-> TXMASKI */
MGETL A0StP,A0FrP,[D1RtP] /* Get frame values */
OR TXMASKI,D1Ar5,D1Ar3 /* New TXMASKI */
B $LSwitchCmn
.size ___TBISyncResume,.-___TBISyncResume
/*
* void __TBIJump( TBIX64 ArgsA, TBIX32 ArgsB, int TrigsMask,
* void (*fnMain)(), void *pStack );
*
* Jump directly to a new routine on an arbitrary stack with arbitrary args
* oring bits back into TXMASKI on route.
*/
.text
.balign 4
.global ___TBIJump
.type ___TBIJump,function
___TBIJump:
XOR D0Re0,D0Re0,D0Re0 /* D0Re0 = 0 */
MOV A0StP,D0Ar6 /* Stack = Frame */
SWAP D0Re0,TXMASKI /* D0Re0 <-> TXMASKI */
MOV A0FrP,D0Ar6
MOVT A1LbP,#HI(__exit)
ADD A1LbP,A1LbP,#LO(__exit)
MOV D1RtP,A1LbP /* D1RtP = __exit */
OR TXMASKI,D0Re0,D0Ar4 /* New TXMASKI */
MOV PC,D1Ar5 /* Jump to fnMain */
.size ___TBIJump,.-___TBIJump
/*
* PTBICTX __TBISwitchInit( void *pStack, int (*fnMain)(),
* .... 4 extra 32-bit args .... );
*
* Generate a new soft thread context ready for it's first outing.
*
* D1Ar1 - Region of memory to be used as the new soft thread stack
* D0Ar2 - Main line routine for new soft thread
* D1Ar3, D0Ar4, D1Ar5, D0Ar6 - arguments to be passed on stack
* The routine returns the initial PTBICTX value for the new thread
*/
.text
.balign 4
.global ___TBISwitchInit
.type ___TBISwitchInit,function
___TBISwitchInit:
MOV D0FrT,A0FrP /* Need save return point */
ADD A0FrP,A0StP,#0
SETL [A0StP++],D0FrT,D1RtP /* Save return to caller */
MOVT A1LbP,#HI(__exit)
ADD A1LbP,A1LbP,#LO(__exit)
MOV D1RtP,A1LbP /* Get address of __exit */
ADD D1Ar1,D1Ar1,#7 /* Align stack to 64-bits */
ANDMB D1Ar1,D1Ar1,#0xfff8 /* by rounding base up */
MOV A0.2,D1Ar1 /* A0.2 is new stack */
MOV D0FrT,D1Ar1 /* Initial puesdo-frame pointer */
SETL [A0.2++],D0FrT,D1RtP /* Save return to __exit */
MOV D1RtP,D0Ar2
SETL [A0.2++],D0FrT,D1RtP /* Save return to fnMain */
ADD D0FrT,D0FrT,#8 /* Advance puesdo-frame pointer */
MSETL [A0.2],D0Ar6,D0Ar4 /* Save extra initial args */
MOVT D1RtP,#HI(___TBIStart) /* Start up code for new stack */
ADD D1RtP,D1RtP,#LO(___TBIStart)
SETL [A0.2++],D0FrT,D1RtP /* Save return to ___TBIStart */
ADD D0FrT,D0FrT,#(8*3) /* Advance puesdo-frame pointer */
MOV D0Re0,A0.2 /* Return pCtx for new thread */
MOV D1Re0,#0 /* pCtx:0 is default Arg1:Arg2 */
/*
* Generate initial TBICTX state
*/
MOVT D1Ar1,#HI($LSwitchExit) /* Async restore code */
ADD D1Ar1,D1Ar1,#LO($LSwitchExit)
MOVT D0Ar2,#TBICTX_SOFT_BIT /* Only soft thread state */
ADD D0Ar6,A0.2,#TBICTX_BYTES /* New A0StP */
MOV D1Ar5,A1GbP /* Same A1GbP */
MOV D0Ar4,D0FrT /* Initial A0FrP */
MOV D1Ar3,A1LbP /* Same A1LbP */
SETL [A0.2++],D0Ar2,D1Ar1 /* Set header fields */
MSETL [A0.2],D0Re0,D0Ar6,D0Ar4,D0Ar2,D0FrT,D0.5,D0.6,D0.7
MOV D0Ar2,#0 /* Zero values */
MOV D1Ar1,#0
SETL [A0.2++],D0Ar2,D1Ar1 /* Zero CurrRPT, CurrBPOBITS, */
SETL [A0.2++],D0Ar2,D1Ar1 /* CurrMODE, and pCurrCBuf */
MSETL [A0.2],D0Ar6,D0Ar4,D0Ar2,D0FrT D0_5 /* Set DX and then AX regs */
B $LSwitchExit /* All done! */
.size ___TBISwitchInit,.-___TBISwitchInit
.text
.balign 4
.global ___TBIStart
.type ___TBIStart,function
___TBIStart:
MOV D1Ar1,D1Re0 /* Pass TBIRES args to call */
MOV D0Ar2,D0Re0
MGETL D0Re0,D0Ar6,D0Ar4,[A0FrP] /* Get hidden args */
SUB A0StP,A0FrP,#(8*3) /* Entry stack pointer */
MOV A0FrP,D0Re0 /* Entry frame pointer */
MOVT A1LbP,#HI(__exit)
ADD A1LbP,A1LbP,#LO(__exit)
MOV D1RtP,A1LbP /* D1RtP = __exit */
MOV PC,D1Re0 /* Jump into fnMain */
.size ___TBIStart,.-___TBIStart
/*
* End of tbisoft.S
*/
/*
* tbistring.c
*
* Copyright (C) 2001, 2002, 2003, 2005, 2007, 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.
*
* String table functions provided as part of the thread binary interface for
* Meta processors
*/
#include <linux/export.h>
#include <linux/string.h>
#include <asm/tbx.h>
/*
* There are not any functions to modify the string table currently, if these
* are required at some later point I suggest having a seperate module and
* ensuring that creating new entries does not interfere with reading old
* entries in any way.
*/
const TBISTR *__TBIFindStr(const TBISTR *start,
const char *str, int match_len)
{
const TBISTR *search = start;
bool exact = true;
const TBISEG *seg;
if (match_len < 0) {
/* Make match_len always positive for the inner loop */
match_len = -match_len;
exact = false;
} else {
/*
* Also support historic behaviour, which expected match_len to
* include null terminator
*/
if (match_len && str[match_len-1] == '\0')
match_len--;
}
if (!search) {
/* Find global string table segment */
seg = __TBIFindSeg(NULL, TBID_SEG(TBID_THREAD_GLOBAL,
TBID_SEGSCOPE_GLOBAL,
TBID_SEGTYPE_STRING));
if (!seg || seg->Bytes < sizeof(TBISTR))
/* No string table! */
return NULL;
/* Start of string table */
search = seg->pGAddr;
}
for (;;) {
while (!search->Tag)
/* Allow simple gaps which are just zero initialised */
search = (const TBISTR *)((const char *)search + 8);
if (search->Tag == METAG_TBI_STRE) {
/* Reached the end of the table */
search = NULL;
break;
}
if ((search->Len >= match_len) &&
(!exact || (search->Len == match_len + 1)) &&
(search->Tag != METAG_TBI_STRG)) {
/* Worth searching */
if (!strncmp(str, (const char *)search->String,
match_len))
break;
}
/* Next entry */
search = (const TBISTR *)((const char *)search + search->Bytes);
}
return search;
}
const void *__TBITransStr(const char *str, int len)
{
const TBISTR *search = NULL;
const void *res = NULL;
for (;;) {
/* Search onwards */
search = __TBIFindStr(search, str, len);
/* No translation returns NULL */
if (!search)
break;
/* Skip matching entries with no translation data */
if (search->TransLen != METAG_TBI_STRX) {
/* Calculate base of translation string */
res = (const char *)search->String +
((search->Len + 7) & ~7);
break;
}
/* Next entry */
search = (const TBISTR *)((const char *)search + search->Bytes);
}
/* Return base address of translation data or NULL */
return res;
}
EXPORT_SYMBOL(__TBITransStr);
/*
* tbitimer.S
*
* Copyright (C) 2001, 2002, 2007, 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.
*
* TBI timer support routines and data values
*/
.file "tbitimer.S"
/*
* Get data structures and defines from the main C header
*/
#include <asm/tbx.h>
.data
.balign 8
.global ___TBITimeB
.type ___TBITimeB,object
___TBITimeB:
.quad 0 /* Background 'lost' ticks */
.size ___TBITimeB,.-___TBITimeB
.data
.balign 8
.global ___TBITimeI
.type ___TBITimeI,object
___TBITimeI:
.quad 0 /* Interrupt 'lost' ticks */
.size ___TBITimeI,.-___TBITimeI
.data
.balign 8
.global ___TBITimes
.type ___TBITimes,object
___TBITimes:
.long ___TBITimeB /* Table of 'lost' tick values */
.long ___TBITimeI
.size ___TBITimes,.-___TBITimes
/*
* Flag bits for control of ___TBITimeCore
*/
#define TIMER_SET_BIT 1
#define TIMER_ADD_BIT 2
/*
* Initialise or stop timer support
*
* Register Usage: D1Ar1 holds Id, D1Ar2 is initial delay or 0
* D0FrT is used to call ___TBITimeCore
* D0Re0 is used for the result which is TXSTAT_TIMER_BIT
* D0Ar4, D1Ar5, D0Ar6 are all used as scratch
* Other registers are those set by ___TBITimeCore
* A0.3 is assumed to point at ___TBITime(I/B)
*/
.text
.balign 4
.global ___TBITimerCtrl
.type ___TBITimerCtrl,function
___TBITimerCtrl:
MOV D1Ar5,#TIMER_SET_BIT /* Timer SET request */
MOVT D0FrT,#HI(___TBITimeCore) /* Get timer core reg values */
CALL D0FrT,#LO(___TBITimeCore) /* and perform register update */
NEGS D0Ar6,D0Ar2 /* Set flags from time-stamp */
ASR D1Ar5,D0Ar6,#31 /* Sign extend D0Ar6 into D1Ar5 */
SETLNZ [A0.3],D0Ar6,D1Ar5 /* ___TBITime(B/I)=-Start if enable */
MOV PC,D1RtP /* Return */
.size ___TBITimerCtrl,.-___TBITimerCtrl
/*
* Return ___TBITimeStamp value
*
* Register Usage: D1Ar1 holds Id
* D0FrT is used to call ___TBITimeCore
* D0Re0, D1Re0 is used for the result
* D1Ar3, D0Ar4, D1Ar5
* Other registers are those set by ___TBITimeCore
* D0Ar6 is assumed to be the timer value read
* A0.3 is assumed to point at ___TBITime(I/B)
*/
.text
.balign 4
.global ___TBITimeStamp
.type ___TBITimeStamp,function
___TBITimeStamp:
MOV D1Ar5,#0 /* Timer GET request */
MOVT D0FrT,#HI(___TBITimeCore) /* Get timer core reg values */
CALL D0FrT,#LO(___TBITimeCore) /* with no register update */
ADDS D0Re0,D0Ar4,D0Ar6 /* Add current time value */
ADD D1Re0,D1Ar3,D1Ar5 /* to 64-bit signed extend time */
ADDCS D1Re0,D1Re0,#1 /* Support borrow too */
MOV PC,D1RtP /* Return */
.size ___TBITimeStamp,.-___TBITimeStamp
/*
* Perform ___TBITimerAdd logic
*
* Register Usage: D1Ar1 holds Id, D0Ar2 holds value to be added to the timer
* D0Re0 is used for the result - new TIMER value
* D1Ar5, D0Ar6 are used as scratch
* Other registers are those set by ___TBITimeCore
* D0Ar6 is assumed to be the timer value read
* D0Ar4, D1Ar3 is the current value of ___TBITime(B/I)
*/
.text
.balign 4
.global ___TBITimerAdd
.type ___TBITimerAdd,function
___TBITimerAdd:
MOV D1Ar5,#TIMER_ADD_BIT /* Timer ADD request */
MOVT D0FrT,#HI(___TBITimeCore) /* Get timer core reg values */
CALL D0FrT,#LO(___TBITimeCore) /* with no register update */
ADD D0Re0,D0Ar2,D0Ar6 /* Regenerate new value = result */
NEG D0Ar2,D0Ar2 /* Negate delta */
ASR D1Re0,D0Ar2,#31 /* Sign extend negated delta */
ADDS D0Ar4,D0Ar4,D0Ar2 /* Add time added to ... */
ADD D1Ar3,D1Ar3,D1Re0 /* ... real timer ... */
ADDCS D1Ar3,D1Ar3,#1 /* ... with carry */
SETL [A0.3],D0Ar4,D1Ar3 /* Update ___TBITime(B/I) */
MOV PC,D1RtP /* Return */
.size ___TBITimerAdd,.-___TBITimerAdd
#ifdef TBI_1_4
/*
* Perform ___TBITimerDeadline logic
* NB: Delays are positive compared to the Wait values which are -ive
*
* Register Usage: D1Ar1 holds Id
* D0Ar2 holds Delay requested
* D0Re0 is used for the result - old TIMER Delay value
* D1Ar5, D0Ar6 are used as scratch
* Other registers are those set by ___TBITimeCore
* D0Ar6 is assumed to be the timer value read
* D0Ar4, D1Ar3 is the current value of ___TBITime(B/I)
*
*/
.text
.type ___TBITimerDeadline,function
.global ___TBITimerDeadline
.align 2
___TBITimerDeadline:
MOV D1Ar5,#TIMER_SET_BIT /* Timer SET request */
MOVT D0FrT,#HI(___TBITimeCore) /* Get timer core reg values */
CALL D0FrT,#LO(___TBITimeCore) /* with no register update */
MOV D0Re0,D0Ar6 /* Old value read = result */
SUB D0Ar2,D0Ar6,D0Ar2 /* Delta from (old - new) */
ASR D1Re0,D0Ar2,#31 /* Sign extend delta */
ADDS D0Ar4,D0Ar4,D0Ar2 /* Add time added to ... */
ADD D1Ar3,D1Ar3,D1Re0 /* ... real timer ... */
ADDCS D1Ar3,D1Ar3,#1 /* ... with carry */
SETL [A0.3],D0Ar4,D1Ar3 /* Update ___TBITime(B/I) */
MOV PC,D1RtP /* Return */
.size ___TBITimerDeadline,.-___TBITimerDeadline
#endif /* TBI_1_4 */
/*
* Perform core timer access logic
*
* Register Usage: D1Ar1 holds Id, D0Ar2 holds input value for SET and
* input value for ADD
* D1Ar5 controls op as SET or ADD as bit values
* On return D0Ar6, D1Ar5 holds the old 64-bit timer value
* A0.3 is setup to point at ___TBITime(I/B)
* A1.3 is setup to point at ___TBITimes
* D0Ar4, D1Ar3 is setup to value of ___TBITime(I/B)
*/
.text
.balign 4
.global ___TBITimeCore
.type ___TBITimeCore,function
___TBITimeCore:
#ifndef METAC_0_1
TSTT D1Ar1,#HI(TBID_ISTAT_BIT) /* Interrupt level timer? */
#endif
MOVT A1LbP,#HI(___TBITimes)
ADD A1LbP,A1LbP,#LO(___TBITimes)
MOV A1.3,A1LbP /* Get ___TBITimes address */
#ifndef METAC_0_1
BNZ $LTimeCoreI /* Yes: Service TXTIMERI! */
#endif
LSRS D1Ar5,D1Ar5,#1 /* Carry = SET, Zero = !ADD */
GETD A0.3,[A1.3+#0] /* A0.3 == &___TBITimeB */
MOV D0Ar6,TXTIMER /* Always GET old value */
MOVCS TXTIMER,D0Ar2 /* Conditional SET operation */
ADDNZ TXTIMER,D0Ar2,D0Ar6 /* Conditional ADD operation */
#ifndef METAC_0_1
B $LTimeCoreEnd
$LTimeCoreI:
LSRS D1Ar5,D1Ar5,#1 /* Carry = SET, Zero = !ADD */
GETD A0.3,[A1.3+#4] /* A0.3 == &___TBITimeI */
MOV D0Ar6,TXTIMERI /* Always GET old value */
MOVCS TXTIMERI,D0Ar2 /* Conditional SET operation */
ADDNZ TXTIMERI,D0Ar2,D0Ar6 /* Conditional ADD operation */
$LTimeCoreEnd:
#endif
ASR D1Ar5,D0Ar6,#31 /* Sign extend D0Ar6 into D1Ar5 */
GETL D0Ar4,D1Ar3,[A0.3] /* Read ___TBITime(B/I) */
MOV PC,D0FrT /* Return quickly */
.size ___TBITimeCore,.-___TBITimeCore
/*
* End of tbitimer.S
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment