summaryrefslogtreecommitdiff
path: root/arch/metag/tbx/tbidefr.S
blob: 3eb165ebf5408abf70a99035d71cf633a2e1b5ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * 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
 */