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
*/
This diff is collapsed.
/*
* 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
*/
This diff is collapsed.
/*
* 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