xtos-internal.h
12.6 KB
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/*
* xtos-internal.h -- internal definitions for single-threaded run-time
*
* Copyright (c) 2003-2010 Tensilica Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XTOS_INTERNAL_H
#define XTOS_INTERNAL_H
#include <xtensa/config/core.h>
#include <xtensa/xtruntime.h>
#include <xtensa/xtruntime-frames.h>
#include <xtensa/xtensa-versions.h>
#ifndef XTOS_PARAMS_H /* this to allow indirect inclusion of this header from the outside */
#include "xtos-params.h"
#endif
/* Relative ordering of subpriorities within an interrupt level (or vector): */
#define XTOS_SPO_ZERO_LO 0 /* lower (eg. zero) numbered interrupts are lower priority than higher numbered interrupts */
#define XTOS_SPO_ZERO_HI 1 /* lower (eg. zero) numbered interrupts are higher priority than higher numbered interrupts */
/* Sanity check some parameters from xtos-params.h: */
#if XTOS_LOCKLEVEL < XCHAL_EXCM_LEVEL || XTOS_LOCKLEVEL > 15
# error Invalid XTOS_LOCKLEVEL value, must be >= EXCM_LEVEL and <= 15, please fix xtos-params.h
#endif
/* Mask of interrupts locked out at XTOS_LOCKLEVEL: */
#define XTOS_LOCKOUT_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(XTOS_LOCKLEVEL)
/* Mask of interrupts that can still be enabled at XTOS_LOCKLEVEL: */
#define XTOS_UNLOCKABLE_MASK (0xFFFFFFFF-XTOS_LOCKOUT_MASK)
/* Don't set this: */
#define XTOS_HIGHINT_TRAMP 0 /* mapping high-pri ints to low-pri not auto-supported */
#define XTOS_VIRTUAL_INTERRUPT XTOS_HIGHINT_TRAMP /* partially-virtualized INTERRUPT register not currently supported */
#if XTOS_HIGHINT_TRAMP
# error Automatically-generated high-level interrupt trampolines are not presently supported.
#endif
/*
* If single interrupt at level-one, sub-prioritization is irrelevant:
*/
#if defined(XCHAL_INTLEVEL1_NUM)
# undef XTOS_SUBPRI
# define XTOS_SUBPRI 0 /* override - only one interrupt */
#endif
/*
* In XEA1, the INTENABLE special register must be virtualized to provide
* standard XTOS functionality.
* In XEA2, this is only needed for software interrupt prioritization.
*/
#if XTOS_SUBPRI || XCHAL_HAVE_XEA1
#define XTOS_VIRTUAL_INTENABLE 1
#else
#define XTOS_VIRTUAL_INTENABLE 0
#endif
/*
* If single interrupt per priority, then fairness is irrelevant:
*/
#if (XTOS_SUBPRI && !XTOS_SUBPRI_GROUPS) || defined(XCHAL_INTLEVEL1_NUM)
# undef XTOS_INT_FAIRNESS
# define XTOS_INT_FAIRNESS 0
#endif
/* Identify special case interrupt handling code in int-lowpri-dispatcher.S: */
#define XTOS_INT_SPECIALCASE (XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI && XTOS_INT_FAIRNESS == 0 && XTOS_SUBPRI_GROUPS == 0)
/*
* Determine whether to extend the interrupt entry array:
*/
#define XIE_EXTEND (XTOS_VIRTUAL_INTENABLE && !XTOS_INT_SPECIALCASE)
/* If we have the NSAU instruction, ordering of interrupts is reversed in _xtos_interrupt_table[]: */
#if XCHAL_HAVE_NSA
# define MAPINT(n) ((XCHAL_NUM_INTERRUPTS-1)-(n))
# ifdef _ASMLANGUAGE
.macro mapint an
neg \an, \an
addi \an, \an, XCHAL_NUM_INTERRUPTS-1
.endm
# endif
#else /* no NSA */
# define MAPINT(n) (n)
# ifdef _ASMLANGUAGE
.macro mapint an
.endm
# endif
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
/*********** Useful macros ***********/
/*
* A useful looping macro:
* 'iterate' invokes 'what' (an instruction, pseudo-op or other macro)
* multiple times, passing it a numbered parameter from 'from' to 'to'
* inclusively. Does not invoke 'what' at all if from > to.
* Maximum difference between 'from' and 'to' is 99 minus nesting depth
* (GNU 'as' doesn't allow nesting deeper than 100).
*/
.macro iterate from, to, what
.ifeq ((\to-\from) & ~0xFFF)
\what \from
iterate "(\from+1)", \to, \what
.endif
.endm // iterate
// rsilft
//
// Execute RSIL \ar, \tolevel if \tolevel is different than \fromlevel.
// This way the RSIL is avoided if we know at assembly time that
// it will not change the level. Typically, this means the \ar register
// is ignored, ie. RSIL is used only to change PS.INTLEVEL.
//
.macro rsilft ar, fromlevel, tolevel
#if XCHAL_HAVE_INTERRUPTS
.if \fromlevel - \tolevel
rsil \ar, \tolevel
.endif
#endif
.endm
// Save LOOP and MAC16 registers, if configured, to the exception stack
// frame pointed to by address register \esf, using \aa and \ab as temporaries.
//
// This macro essentially saves optional registers that the compiler uses by
// default when present.
// Note that the acclo/acchi subset of MAC16 may be used even if others
// multipliers are present (e.g. mul16, mul32).
//
// Only two temp registers required for this code to be optimal (no interlocks) in both
// T10xx (Athens) and Xtensa LX microarchitectures (both 5 and 7 stage pipes):
//
.macro save_loops_mac16 esf, aa, ab
#if XCHAL_HAVE_LOOPS
rsr \aa, LCOUNT
rsr \ab, LBEG
s32i \aa, \esf, UEXC_lcount
rsr \aa, LEND
s32i \ab, \esf, UEXC_lbeg
s32i \aa, \esf, UEXC_lend
#endif
#if XCHAL_HAVE_MAC16
rsr \aa, ACCLO
rsr \ab, ACCHI
s32i \aa, \esf, UEXC_acclo
s32i \ab, \esf, UEXC_acchi
# if XTOS_SAVE_ALL_MAC16
rsr \aa, M0
rsr \ab, M1
s32i \aa, \esf, UEXC_mr + 0
s32i \ab, \esf, UEXC_mr + 4
rsr \aa, M2
rsr \ab, M3
s32i \aa, \esf, UEXC_mr + 8
s32i \ab, \esf, UEXC_mr + 12
# endif
#endif
.endm
// Restore LOOP and MAC16 registers, if configured, from the exception stack
// frame pointed to by address register \esf, using \aa, \ab and \ac as temporaries.
//
// Three temp registers are required for this code to be optimal (no interlocks) in
// Xtensa LX microarchitectures with 7-stage pipe; otherwise only two
// registers would be needed.
//
.macro restore_loops_mac16 esf, aa, ab, ac
#if XCHAL_HAVE_LOOPS
l32i \aa, \esf, UEXC_lcount
l32i \ab, \esf, UEXC_lbeg
l32i \ac, \esf, UEXC_lend
wsr \aa, LCOUNT
wsr \ab, LBEG
wsr \ac, LEND
#endif
#if XCHAL_HAVE_MAC16
l32i \aa, \esf, UEXC_acclo
l32i \ab, \esf, UEXC_acchi
# if XTOS_SAVE_ALL_MAC16
l32i \ac, \esf, UEXC_mr + 0
wsr \aa, ACCLO
wsr \ab, ACCHI
wsr \ac, M0
l32i \aa, \esf, UEXC_mr + 4
l32i \ab, \esf, UEXC_mr + 8
l32i \ac, \esf, UEXC_mr + 12
wsr \aa, M1
wsr \ab, M2
wsr \ac, M3
# else
wsr \aa, ACCLO
wsr \ab, ACCHI
# endif
#endif
.endm
/* Offsets from _xtos_intstruct structure: */
.struct 0
#if XTOS_VIRTUAL_INTENABLE
XTOS_ENABLED_OFS: .space 4 /* _xtos_enabled variable */
XTOS_VPRI_ENABLED_OFS: .space 4 /* _xtos_vpri_enabled variable */
#endif
#if XTOS_VIRTUAL_INTERRUPT
XTOS_PENDING_OFS: .space 4 /* _xtos_pending variable */
#endif
.text
#if XTOS_VIRTUAL_INTENABLE
// Update INTENABLE register, computing it as follows:
// INTENABLE = _xtos_enabled & _xtos_vpri_enabled
// [ & ~_xtos_pending ]
//
// Entry:
// register ax = &_xtos_intstruct
// register ay, az undefined (temporaries)
// PS.INTLEVEL set to XTOS_LOCKLEVEL or higher (eg. via xtos_lock)
// window overflows prevented (PS.WOE=0, PS.EXCM=1, or overflows
// already done for registers ax, ay, az)
//
// Exit:
// registers ax, ay, az clobbered
// PS unchanged
// caller needs to SYNC (?) for INTENABLE changes to take effect
//
// Note: in other software prioritization schemes/implementations,
// the term <_xtos_vpri_enabled> in the above expression is often
// replaced with another expression that computes the set of
// interrupts allowed to be enabled at the current software virtualized
// interrupt priority.
//
// For example, a simple alternative implementation of software
// prioritization for XTOS might have been the following:
// INTENABLE = _xtos_enabled & (vpri_enabled | UNLOCKABLE_MASK)
// which removes the need for the interrupt dispatcher to 'or' the
// UNLOCKABLE_MASK bits into _xtos_vpri_enabled, and lets other code
// disable all lockout level interrupts by just clearing _xtos_vpri_enabled
// rather than setting it to UNLOCKABLE_MASK.
// Other implementations sometimes use a table, eg:
// INTENABLE = _xtos_enabled & enable_table[current_vpri]
// The HAL (used by some 3rd party OSes) uses essentially a table-driven
// version, with other tables enabling run-time changing of priorities.
//
.macro xtos_update_intenable ax, ay, az
//movi \ax, _xtos_intstruct
l32i \ay, \ax, XTOS_VPRI_ENABLED_OFS // ay = _xtos_vpri_enabled
l32i \az, \ax, XTOS_ENABLED_OFS // az = _xtos_enabled
//interlock
and \az, \az, \ay // az = _xtos_enabled & _xtos_vpri_enabled
# if XTOS_VIRTUAL_INTERRUPT
l32i \ay, \ax, XTOS_PENDING_OFS // ay = _xtos_pending
movi \ax, -1
xor \ay, \ay, \ax // ay = ~_xtos_pending
and \az, \az, \ay // az &= ~_xtos_pending
# endif
wsr \az, INTENABLE
.endm
#endif /* VIRTUAL_INTENABLE */
.macro xtos_lock ax
rsil \ax, XTOS_LOCKLEVEL // lockout
.endm
.macro xtos_unlock ax
wsr \ax, PS // unlock
rsync
.endm
/* Offsets to XtosIntHandlerEntry structure fields (see below): */
# define XIE_HANDLER 0
# define XIE_ARG 4
# define XIE_SIZE 8
# if XIE_EXTEND
# define XIE_VPRIMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+0) /* if VIRTUAL_INTENABLE [SUBPRI||XEA1] && !SPECIALCASE */
# define XIE_LEVELMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+4) /* [fairness preloop] if FAIRNESS && SUBPRI [&& SUBPRI_GROUPS] */
# endif
/* To simplify code: */
# if XCHAL_HAVE_NSA
# define IFNSA(a,b) a
# else
# define IFNSA(a,b) b
# endif
#else /* !_ASMLANGUAGE && !__ASSEMBLER__ */
/*
* Interrupt handler table entry.
* Unregistered entries have 'handler' point to _xtos_unhandled_interrupt().
*/
typedef struct XtosIntHandlerEntry {
_xtos_handler handler;
void * arg;
} XtosIntHandlerEntry;
# if XIE_EXTEND
typedef struct XtosIntMaskEntry {
unsigned vpri_mask; /* mask of interrupts enabled when this interrupt is taken */
unsigned level_mask; /* mask of interrupts at this interrupt's level */
} XtosIntMaskEntry;
# endif
#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */
/*
* Notes...
*
* XEA1 and interrupt-SUBPRIoritization both imply virtualization of INTENABLE.
* Synchronous trampoloines imply partial virtualization of the INTERRUPT
* register, which in turn also implies virtualization of INTENABLE register.
* High-level interrupts manipulating the set of enabled interrupts implies
* at least a high XTOS_LOCK_LEVEL, although not necessarily INTENABLE virtualization.
*
* With INTENABLE register virtualization, at all times the INTENABLE
* register reflects the expression:
* (set of interrupts enabled) & (set of interrupts enabled by current
* virtual priority)
*
* Unrelated (DBREAK semantics):
*
* A[31-6] = DBA[3-6]
* ---------------------
* A[5-0] & DBC[5-C] & szmask
*
* = DBA[5-0] & szmask
* ^___ ???
*/
/* Report whether the XSR instruction is available (conservative): */
#define HAVE_XSR (XCHAL_HAVE_XEA2 || !XCHAL_HAVE_EXCEPTIONS)
/*
* This is more accurate, but not a reliable test in software releases prior to 6.0
* (where the targeted hardware parameter was not explicit in the XPG):
*
*#define HAVE_XSR (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_T1040_0)
*/
/* Macros for supporting hi-level and medium-level interrupt handling. */
#if XCHAL_NUM_INTLEVELS > 6
#error Template files (*-template.S) limit support to interrupt levels <= 6
#endif
#if defined(__XTENSA_WINDOWED_ABI__) && XCHAL_HAVE_CALL4AND12 == 0
#error CALL8-only is not supported!
#endif
#define INTERRUPT_IS_HI(level) \
( XCHAL_HAVE_INTERRUPTS && \
(XCHAL_EXCM_LEVEL < level) && \
(XCHAL_NUM_INTLEVELS >= level) && \
(XCHAL_HAVE_DEBUG ? XCHAL_DEBUGLEVEL != level : 1))
#define INTERRUPT_IS_MED(level) \
(XCHAL_HAVE_INTERRUPTS && (XCHAL_EXCM_LEVEL >= level))
#define _JOIN(x,y) x ## y
#define JOIN(x,y) _JOIN(x,y)
#define _JOIN3(a,b,c) a ## b ## c
#define JOIN3(a,b,c) _JOIN3(a,b,c)
#define LABEL(x,y) JOIN3(x,_INTERRUPT_LEVEL,y)
#define EXCSAVE_LEVEL JOIN(EXCSAVE_,_INTERRUPT_LEVEL)
#define INTLEVEL_VSIZE JOIN3(XSHAL_INTLEVEL,_INTERRUPT_LEVEL,_VECTOR_SIZE)
#endif /* XTOS_INTERNAL_H */