OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rtems-20020807/] [doc/] [porting/] [interrupts.t] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
@c
2
@c  COPYRIGHT (c) 1988-2002.
3
@c  On-Line Applications Research Corporation (OAR).
4
@c  All rights reserved.
5
@c
6
@c  interrupts.t,v 1.6 2002/01/17 21:47:45 joel Exp
7
@c
8
 
9
@chapter Interrupts
10
 
11
@section Introduction
12
 
13
@section Interrupt Levels
14
 
15
RTEMS is designed assuming that a CPU family has a level associated with
16
interrupts.  Interrupts below the current interrupt level are masked and
17
do not interrupt the CPU until the interrupt level is lowered.  This
18
design provides for 256 distinct interrupt levels even though most CPU
19
implementations support far fewer levels.  Interrupt level 0 is assumed to
20
map to the hardware settings for all interrupts enabled.
21
 
22
Over the years that RTEMS has been available, there has been much
23
discussion on how to handle CPU families which support very few interrupt
24
levels such as the i386, PowerPC, and HP-PA RISC. XXX
25
 
26
@subsection Interrupt Level Mask
27
 
28
The CPU_MODES_INTERRUPT_MASK macro defines the number of bits actually used in the interrupt field of the task mode.  How those bits map to the CPU interrupt levels is defined by the routine _CPU_ISR_Set_level().
29
 
30
The following illustrates how the CPU_MODES_INTERRUPT_MASK is set on a CPU
31
family like the Intel i386 where the CPU itself only recognizes two
32
interrupt levels - enabled and disabled.
33
 
34
@example
35
#define CPU_MODES_INTERRUPT_MASK   0x00000001
36
@end example
37
 
38
 
39
@subsection Obtaining the Current Interrupt Level
40
 
41
The _CPU_ISR_Get_level function returns the current interrupt level.
42
 
43
@example
44
unsigned32 _CPU_ISR_Get_level( void )
45
@end example
46
 
47
@subsection Set the Interrupt Level
48
 
49
The _CPU_ISR_Set_level routine maps the interrupt level in the Classic API
50
task mode onto the hardware that the CPU actually provides.  Currently,
51
interrupt levels that do not map onto the CPU in a generic fashion are
52
undefined.  Someday, it would be nice if these were "mapped" by the
53
application via a callout.  For example, the Motorola m68k has 8 levels 0
54
- 7, and levels 8 - 255 are currently undefined.  Levels 8 - 255 would be
55
available for bsp/application specific meaning. This could be used to
56
manage a programmable interrupt controller via the rtems_task_mode
57
directive.
58
 
59
The following is a dummy implementation of the _CPU_ISR_Set_level routine:
60
 
61
@example
62
#define _CPU_ISR_Set_level( new_level ) \
63
  @{ \
64
  @}
65
@end example
66
 
67
The following is the implementation from the Motorola M68K:
68
 
69
@example
70
XXX insert m68k implementation here
71
@end example
72
 
73
 
74
@subsection Disable Interrupts
75
 
76
The _CPU_ISR_Disable routine disable all external interrupts.  It returns
77
the previous interrupt level in the single parameter _isr_cookie.  This
78
routine is used to disable interrupts during a critical section in the
79
RTEMS executive.  Great care is taken inside the executive to ensure that
80
interrupts are disabled for a minimum length of time.  It is important to
81
note that the way the previous level is returned forces the implementation
82
to be a macro that translates to either inline assembly language or a
83
function call whose return value is placed into _isr_cookie.
84
 
85
It is important for the porter to realize that the value of _isr_cookie
86
has no defined meaning except that it is the most convenient format for
87
the _CPU_ISR_Disable, _CPU_ISR_Enable, and _CPU_ISR_Disable routines to
88
manipulate.  It is typically the contents of the processor status
89
register.  It is NOT the same format as manipulated by the
90
_CPU_ISR_Get_level and _CPU_ISR_Set_level routines. The following is a
91
dummy implementation that simply sets the previous level to 0.
92
 
93
@example
94
#define _CPU_ISR_Disable( _isr_cookie ) \
95
  @{ \
96
    (_isr_cookie) = 0;   /* do something to prevent warnings */ \
97
  @}
98
@end example
99
 
100
The following is the implementation from the Motorola M68K port:
101
 
102
@example
103
XXX insert m68k port here
104
@end example
105
 
106
@subsection Enable Interrupts
107
 
108
The _CPU_ISR_Enable routines enables interrupts to the previous level
109
(returned by _CPU_ISR_Disable).  This routine is invoked at the end of an
110
RTEMS critical section to reenable interrupts.  The parameter _level is
111
not modified but indicates that level that interrupts should be enabled
112
to.  The following illustrates a dummy implementation of the
113
_CPU_ISR_Enable routine:
114
 
115
@example
116
#define _CPU_ISR_Enable( _isr_cookie )  \
117
  @{ \
118
  @}
119
@end example
120
 
121
The following is the implementation from the Motorola M68K port:
122
 
123
@example
124
XXX insert m68k version here
125
@end example
126
 
127
 
128
@subsection Flash Interrupts
129
 
130
The _CPU_ISR_Flash routine temporarily restores the interrupt to _level
131
before immediately disabling them again.  This is used to divide long
132
RTEMS critical sections into two or more parts.  This routine is always
133
preceded by a call to _CPU_ISR_Disable and followed by a call to
134
_CPU_ISR_Enable.  The parameter _level is not modified.
135
 
136
The following is a dummy implementation of the _CPU_ISR_Flash routine:
137
 
138
@example
139
#define _CPU_ISR_Flash( _isr_cookie ) \
140
  @{ \
141
  @}
142
@end example
143
 
144
The following is the implementation from the Motorola M68K port:
145
 
146
@example
147
XXX insert m68k version here
148
@end example
149
 
150
 
151
@section Interrupt Stack Management
152
 
153
@subsection Hardware or Software Managed Interrupt Stack
154
 
155
The setting of the CPU_HAS_SOFTWARE_INTERRUPT_STACK indicates whether the
156
interrupt stack is managed by RTEMS in software or the CPU has direct
157
support for an interrupt stack.  If RTEMS is to manage a dedicated
158
interrupt stack in software, then this macro should be set to TRUE and the
159
memory for the software managed interrupt stack is allocated in
160
@code{_ISR_Handler_initialization}.  If this macro is set to FALSE, then
161
RTEMS assumes that the hardware managed interrupt stack is supported by
162
this CPU.  If the CPU has a hardware managed interrupt stack, then the
163
porter has the option of letting the BSP allcoate and initialize the
164
interrupt stack or letting RTEMS do this.  If RTEMS is to allocate the
165
memory for the interrupt stack, then the macro
166
CPU_ALLOCATE_INTERRUPT_STACK should be set to TRUE.  If this macro is set
167
to FALSE, then it is the responsibility of the BSP to allocate the memory
168
for this stack and initialize it.
169
 
170
If the CPU does not support a dedicated interrupt stack, then the porter
171
has two options: (1) execute interrupts on the stack of the interrupted
172
task, and (2) have RTEMS manage a dedicated interrupt stack.
173
 
174
NOTE: If CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE, then the macro
175
CPU_ALLOCATE_INTERRUPT_STACK should also be set to TRUE.
176
 
177
Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
178
CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE.  It is possible
179
that both are FALSE for a particular CPU.  Although it is unclear what
180
that would imply about the interrupt processing procedure on that CPU.
181
 
182
@subsection Allocation of Interrupt Stack Memory
183
 
184
Whether or not the interrupt stack is hardware or software managed, RTEMS
185
may allocate memory for the interrupt stack from the Executive Workspace.
186
If RTEMS is going to allocate the memory for a dedicated interrupt stack
187
in the Interrupt Manager, then the macro CPU_ALLOCATE_INTERRUPT_STACK
188
should be set to TRUE.
189
 
190
NOTE: This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE.
191
 
192
@example
193
#define CPU_ALLOCATE_INTERRUPT_STACK TRUE
194
@end example
195
 
196
If the CPU_HAS_SOFTWARE_INTERRUPT_STACK macro is set to TRUE, then RTEMS automatically allocates the stack memory in the initialization of the Interrupt Manager and the switch to that stack is performed in @code{_ISR_Handler} on the outermost interrupt.  The _CPU_Interrupt_stack_low and _CPU_Interrupt_stack_high variables contain the addresses of the the lowest and highest addresses of the memory allocated for the interrupt stack.  Although technically only one of these addresses is required to switch to the interrupt stack, by always providing both addresses, the port has more options avaialble to it without requiring modifications to the portable parts of the executive.  Whether the stack  grows up or down, this give the CPU dependent code the option of picking the version it wants to use.
197
 
198
@example
199
SCORE_EXTERN void               *_CPU_Interrupt_stack_low;
200
SCORE_EXTERN void               *_CPU_Interrupt_stack_high;
201
@end example
202
 
203
NOTE: These two variables are required if the macro
204
CPU_HAS_SOFTWARE_INTERRUPT_STACK is defined as TRUE.
205
 
206
@subsection Install the Interrupt Stack
207
 
208
The _CPU_Install_interrupt_stack routine XXX
209
 
210
This routine installs the hardware interrupt stack pointer.
211
 
212
NOTE:  It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STAC is TRUE.
213
 
214
@example
215
void _CPU_Install_interrupt_stack( void )
216
@end example
217
 
218
 
219
@section ISR Installation
220
 
221
@subsection Install a Raw Interrupt Handler
222
 
223
The _CPU_ISR_install_raw_handler XXX
224
 
225
@example
226
void _CPU_ISR_install_raw_handler(
227
  unsigned32  vector,
228
  proc_ptr    new_handler,
229
  proc_ptr   *old_handler
230
)
231
@end example
232
 
233
This is where we install the interrupt handler into the "raw" interrupt
234
table used by the CPU to dispatch interrupt handlers.
235
 
236
@subsection Interrupt Context
237
 
238
@subsection Maximum Number of Vectors
239
 
240
There are two related macros used to defines the number of entries in the
241
_ISR_Vector_table managed by RTEMS.  The macro
242
CPU_INTERRUPT_NUMBER_OF_VECTORS is the actual number of vectors supported
243
by this CPU model.  The second macro is the
244
CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER.  Since the table is zero-based, this
245
indicates the highest vector number which can be looked up in the table
246
and mapped into a user provided handler.
247
 
248
@example
249
#define CPU_INTERRUPT_NUMBER_OF_VECTORS      32
250
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER \
251
        (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
252
@end example
253
 
254
 
255
@subsection Install RTEMS Interrupt Handler
256
 
257
The _CPU_ISR_install_vector routine installs the RTEMS handler for the
258
specified vector.
259
 
260
XXX Input parameters:
261
vector      - interrupt vector number
262
old_handler - former ISR for this vector number
263
new_handler - replacement ISR for this vector number
264
 
265
@example
266
void _CPU_ISR_install_vector(
267
  unsigned32  vector,
268
  proc_ptr    new_handler,
269
  proc_ptr   *old_handler
270
)
271
@end example
272
 
273
@example
274
*old_handler = _ISR_Vector_table[ vector ];
275
@end example
276
 
277
If the interrupt vector table is a table of pointer to isr entry points,
278
then we need to install the appropriate RTEMS interrupt handler for this
279
vector number.
280
 
281
@example
282
_CPU_ISR_install_raw_handler( vector, new_handler, old_handler );
283
@end example
284
 
285
We put the actual user ISR address in _ISR_vector_table.  This will be
286
used by the @code{_ISR_Handler} so the user gets control.
287
 
288
@example
289
_ISR_Vector_table[ vector ] = new_handler;
290
@end example
291
 
292
@section Interrupt Processing
293
 
294
@subsection Interrupt Frame Data Structure
295
 
296
When an interrupt occurs, it is the responsibility of the interrupt
297
dispatching software to save the context of the processor such that an ISR
298
written in a high-level language (typically C) can be invoked without
299
damaging the state of the task that was interrupted.  In general, this
300
results in the saving of registers which are NOT preserved across
301
subroutine calls as well as any special interrupt state.  A port should
302
define the CPU_Interrupt_frame structure so that application code can
303
examine the saved state.
304
 
305
@example
306
typedef struct @{
307
    unsigned32 not_preserved_register_1;
308
    unsigned32 special_interrupt_register;
309
@} CPU_Interrupt_frame;
310
@end example
311
 
312
 
313
@subsection Interrupt Dispatching
314
 
315
The @code{_ISR_Handler} routine provides the RTEMS interrupt management.
316
 
317
@example
318
void _ISR_Handler()
319
@end example
320
 
321
This discussion ignores a lot of the ugly details in a real implementation
322
such as saving enough registers/state to be able to do something real.
323
Keep in mind that the goal is to invoke a user's ISR handler which is
324
written in C.  That ISR handler uses a known set of registers thus
325
allowing the ISR to preserve only those that would normally be corrupted
326
by a subroutine call.
327
 
328
Also note that the exact order is to a large extent flexible.  Hardware
329
will dictate a sequence for a certain subset of @code{_ISR_Handler} while
330
requirements for setting the RTEMS state variables that indicate the
331
interrupt nest level (@code{_ISR_Nest_level}) and dispatching disable
332
level (@code{_Thread_Dispatch_disable_level}) will also
333
restrict the allowable order.
334
 
335
Upon entry to @code{_ISR_Handler}, @code{_Thread_Dispatch_disable_level} is
336
zero if the interrupt occurred while outside an RTEMS service call.
337
Conversely, it will be non-zero if interrupting an RTEMS service
338
call.  Thus, @code{_Thread_Dispatch_disable_level} will always be
339
greater than or equal to @code{_ISR_Nest_level} and not strictly
340
equal.
341
 
342
Upon entry to the "common" @code{_ISR_Handler}, the vector number must be
343
available.  On some CPUs the hardware puts either the vector number or the
344
offset into the vector table for this ISR in a known place.  If the
345
hardware does not provide this information, then the assembly portion of
346
RTEMS for this port will contain a set of distinct interrupt entry points
347
which somehow place the vector number in a known place (which is safe if
348
another interrupt nests this one) and branches to @code{_ISR_Handler}.
349
 
350
@example
351
save some or all context on stack
352
may need to save some special interrupt information for exit
353
 
354
#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
355
    if ( _ISR_Nest_level == 0 )
356
        switch to software interrupt stack
357
#endif
358
_ISR_Nest_level++;
359
_Thread_Dispatch_disable_level++;
360
(*_ISR_Vector_table[ vector ])( vector );
361
--_ISR_Nest_level;
362
if ( _ISR_Nest_level )
363
    goto the label "exit interrupt (simple case)"
364
#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
365
    restore stack
366
#endif
367
 
368
if ( !_Context_Switch_necessary )
369
    goto the label "exit interrupt (simple case)"
370
 
371
if ( !_ISR_Signals_to_thread_executing )
372
    goto the label "exit interrupt (simple case)"
373
 
374
_ISR_Signals_to_thread_executing = FALSE;
375
 
376
call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
377
prepare to get out of interrupt
378
return from interrupt  (maybe to _ISR_Dispatch)
379
 
380
LABEL "exit interrupt (simple case):
381
 prepare to get out of interrupt
382
 return from interrupt
383
@end example
384
 
385
Some ports have the special routine @code{_ISR_Dispatch} because
386
the CPU has a special "interrupt mode" and RTEMS must switch back
387
to the task stack and/or non-interrupt mode before invoking
388
@code{_Thread_Dispatch}.  For example, consider the MC68020 where
389
upon return from the outermost interrupt, the CPU must switch
390
from the interrupt stack to the master stack before invoking
391
@code{_Thread_Dispatch}.  @code{_ISR_Dispatch} is the special port
392
specific wrapper for @code{_Thread_Dispatch} used in this case.
393
 
394
@subsection ISR Invoked with Frame Pointer
395
 
396
Does the RTEMS invoke the user's ISR with the vector number and a pointer
397
to the saved interrupt frame (1) or just the vector number (0)?
398
 
399
@example
400
#define CPU_ISR_PASSES_FRAME_POINTER 0
401
@end example
402
 
403
NOTE: It is desirable to include a pointer to the interrupt stack frame as
404
an argument to the interrupt service routine.  Eventually, it would be
405
nice if all ports included this parameter.
406
 
407
@subsection Pointer to _Thread_Dispatch Routine
408
 
409
With some compilation systems, it is difficult if not impossible to call a
410
high-level language routine from assembly language.  This is especially
411
true of commercial Ada compilers and name mangling C++ ones.  This
412
variable can be optionally defined by the CPU porter and contains the
413
address of the routine _Thread_Dispatch.  This can make it easier to
414
invoke that routine at the end of the interrupt sequence (if a dispatch is
415
necessary).
416
 
417
@example
418
void (*_CPU_Thread_dispatch_pointer)();
419
@end example
420
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.