]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - doc/html/ref/hal-architecture-characterization.html
RedBoot TX53 Release 2012-02-15
[karo-tx-redboot.git] / doc / html / ref / hal-architecture-characterization.html
1 <!-- Copyright (C) 2003 Red Hat, Inc.                                -->
2 <!-- This material may be distributed only subject to the terms      -->
3 <!-- and conditions set forth in the Open Publication License, v1.0  -->
4 <!-- or later (the latest version is presently available at          -->
5 <!-- http://www.opencontent.org/openpub/).                           -->
6 <!-- Distribution of the work or derivative of the work in any       -->
7 <!-- standard (paper) book form is prohibited unless prior           -->
8 <!-- permission is obtained from the copyright holder.               -->
9 <HTML
10 ><HEAD
11 ><TITLE
12 >Architecture Characterization</TITLE
13 ><meta name="MSSmartTagsPreventParsing" content="TRUE">
14 <META
15 NAME="GENERATOR"
16 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
17 "><LINK
18 REL="HOME"
19 TITLE="eCos Reference Manual"
20 HREF="ecos-ref.html"><LINK
21 REL="UP"
22 TITLE="HAL Interfaces"
23 HREF="hal-interfaces.html"><LINK
24 REL="PREVIOUS"
25 TITLE="HAL Interfaces"
26 HREF="hal-interfaces.html"><LINK
27 REL="NEXT"
28 TITLE="Interrupt Handling"
29 HREF="hal-interrupt-handling.html"></HEAD
30 ><BODY
31 CLASS="SECTION"
32 BGCOLOR="#FFFFFF"
33 TEXT="#000000"
34 LINK="#0000FF"
35 VLINK="#840084"
36 ALINK="#0000FF"
37 ><DIV
38 CLASS="NAVHEADER"
39 ><TABLE
40 SUMMARY="Header navigation table"
41 WIDTH="100%"
42 BORDER="0"
43 CELLPADDING="0"
44 CELLSPACING="0"
45 ><TR
46 ><TH
47 COLSPAN="3"
48 ALIGN="center"
49 >eCos Reference Manual</TH
50 ></TR
51 ><TR
52 ><TD
53 WIDTH="10%"
54 ALIGN="left"
55 VALIGN="bottom"
56 ><A
57 HREF="hal-interfaces.html"
58 ACCESSKEY="P"
59 >Prev</A
60 ></TD
61 ><TD
62 WIDTH="80%"
63 ALIGN="center"
64 VALIGN="bottom"
65 >Chapter 9. HAL Interfaces</TD
66 ><TD
67 WIDTH="10%"
68 ALIGN="right"
69 VALIGN="bottom"
70 ><A
71 HREF="hal-interrupt-handling.html"
72 ACCESSKEY="N"
73 >Next</A
74 ></TD
75 ></TR
76 ></TABLE
77 ><HR
78 ALIGN="LEFT"
79 WIDTH="100%"></DIV
80 ><DIV
81 CLASS="SECTION"
82 ><H1
83 CLASS="SECTION"
84 ><A
85 NAME="HAL-ARCHITECTURE-CHARACTERIZATION">Architecture Characterization</H1
86 ><P
87 >These are definition that are related to the basic architecture of the
88 CPU. These include the CPU context save format, context switching, bit
89 twiddling, breakpoints, stack sizes and address translation.</P
90 ><P
91 >Most of these definition are found in
92 <TT
93 CLASS="FILENAME"
94 >cyg/hal/hal_arch.h</TT
95 >.  This file is supplied by the
96 architecture HAL. If there are variant or platform specific
97 definitions then these will be found in
98 <TT
99 CLASS="FILENAME"
100 >cyg/hal/var_arch.h</TT
101 > or
102 <TT
103 CLASS="FILENAME"
104 >cyg/hal/plf_arch.h</TT
105 >. These files are include
106 automatically by this header, so need not be included explicitly.</P
107 ><DIV
108 CLASS="SECTION"
109 ><H2
110 CLASS="SECTION"
111 ><A
112 NAME="AEN7787">Register Save Format</H2
113 ><TABLE
114 BORDER="5"
115 BGCOLOR="#E0E0F0"
116 WIDTH="70%"
117 ><TR
118 ><TD
119 ><PRE
120 CLASS="PROGRAMLISTING"
121 >typedef struct HAL_SavedRegisters
122 {
123     /* architecture-dependent list of registers to be saved */ 
124 } HAL_SavedRegisters;</PRE
125 ></TD
126 ></TR
127 ></TABLE
128 ><P
129 >This structure describes the layout of a saved machine state on the
130 stack. Such states are saved during thread context switches,
131 interrupts and exceptions. Different quantities of state may be saved
132 during each of these, but usually a thread context state is a subset
133 of the interrupt state which is itself a subset of an exception state.
134 For debugging purposes, the same structure is used for all three
135 purposes, but where these states are significantly different, this
136 structure may contain a union of the three states.</P
137 ></DIV
138 ><DIV
139 CLASS="SECTION"
140 ><H2
141 CLASS="SECTION"
142 ><A
143 NAME="AEN7791">Thread Context Initialization</H2
144 ><TABLE
145 BORDER="5"
146 BGCOLOR="#E0E0F0"
147 WIDTH="70%"
148 ><TR
149 ><TD
150 ><PRE
151 CLASS="PROGRAMLISTING"
152 >HAL_THREAD_INIT_CONTEXT( sp, arg, entry, id )</PRE
153 ></TD
154 ></TR
155 ></TABLE
156 ><P
157 >This macro initializes a thread's context so that
158 it may be switched to by <TT
159 CLASS="FUNCTION"
160 >HAL_THREAD_SWITCH_CONTEXT()</TT
161 >.
162 The arguments are:</P
163 ><P
164 ></P
165 ><DIV
166 CLASS="VARIABLELIST"
167 ><DL
168 ><DT
169 >sp</DT
170 ><DD
171 ><P
172 >      A location containing the current value of the thread's stack
173       pointer. This should be a variable or a structure field. The SP
174       value will be read out of here and an adjusted value written
175       back.
176       </P
177 ></DD
178 ><DT
179 >arg</DT
180 ><DD
181 ><P
182 >      A value that is passed as the first argument to the entry
183       point function.
184       </P
185 ></DD
186 ><DT
187 >entry</DT
188 ><DD
189 ><P
190 >      The address of an entry point function. This will be called
191       according the C calling conventions, and the value of
192       <TT
193 CLASS="PARAMETER"
194 ><I
195 >arg</I
196 ></TT
197 > will be passed as the first
198       argument. This function should have the following type signature
199       <TT
200 CLASS="FUNCTION"
201 >void entry(CYG_ADDRWORD arg)</TT
202 >.
203       </P
204 ></DD
205 ><DT
206 >id</DT
207 ><DD
208 ><P
209 >      A thread id value. This is only used for debugging purposes,
210       it is ORed into the initialization pattern for unused registers
211       and may be used to help identify the thread from its register dump.
212       The least significant 16 bits of this value should be zero to allow
213       space for a register identifier.
214       </P
215 ></DD
216 ></DL
217 ></DIV
218 ></DIV
219 ><DIV
220 CLASS="SECTION"
221 ><H2
222 CLASS="SECTION"
223 ><A
224 NAME="HAL-CONTEXT-SWITCH">Thread Context Switching</H2
225 ><TABLE
226 BORDER="5"
227 BGCOLOR="#E0E0F0"
228 WIDTH="70%"
229 ><TR
230 ><TD
231 ><PRE
232 CLASS="PROGRAMLISTING"
233 >HAL_THREAD_LOAD_CONTEXT( to )
234 HAL_THREAD_SWITCH_CONTEXT( from, to )</PRE
235 ></TD
236 ></TR
237 ></TABLE
238 ><P
239 >These macros implement the thread switch code. The arguments are:</P
240 ><P
241 ></P
242 ><DIV
243 CLASS="VARIABLELIST"
244 ><DL
245 ><DT
246 >from</DT
247 ><DD
248 ><P
249 >      A pointer to a location where the stack pointer of the current
250       thread will be stored.
251       </P
252 ></DD
253 ><DT
254 >to</DT
255 ><DD
256 ><P
257 >      A pointer to a location from where the stack pointer of the next
258       thread will be read.
259       </P
260 ></DD
261 ></DL
262 ></DIV
263 ><P
264 >For <TT
265 CLASS="FUNCTION"
266 >HAL_THREAD_LOAD_CONTEXT()</TT
267 > the current CPU
268 state is discarded and the state of the destination thread is
269 loaded. This is only used once, to load the first thread when the
270 scheduler is started.</P
271 ><P
272 >For <TT
273 CLASS="FUNCTION"
274 >HAL_THREAD_SWITCH_CONTEXT()</TT
275 > the state of the
276 current thread is saved onto its stack, using the current value of the
277 stack pointer, and the address of the saved state placed in
278 <TT
279 CLASS="PARAMETER"
280 ><I
281 >*from</I
282 ></TT
283 >.  The value in
284 <TT
285 CLASS="PARAMETER"
286 ><I
287 >*to</I
288 ></TT
289 > is then read and the state of the new
290 thread is loaded from it.</P
291 ><P
292 >While these two operations may be implemented with inline assembler,
293 they are normally implemented as calls to assembly code functions in
294 the HAL. There are two advantages to doing it this way. First, the
295 return link of the call provides a convenient PC value to be used in
296 the saved context. Second, the calling conventions mean that the
297 compiler will have already saved the caller-saved registers before the
298 call, so the HAL need only save the callee-saved registers.</P
299 ><P
300 >The implementation of <TT
301 CLASS="FUNCTION"
302 >HAL_THREAD_SWITCH_CONTEXT()</TT
303 >
304 saves the current CPU state on the stack, including the current
305 interrupt state (or at least the register that contains it). For
306 debugging purposes it is useful to save the entire register set, but
307 for performance only the ABI-defined callee-saved registers need be
308 saved. If it is implemented, the option
309 <TT
310 CLASS="LITERAL"
311 >CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM</TT
312 > controls
313 how many registers are saved.</P
314 ><P
315 >The implementation of <TT
316 CLASS="FUNCTION"
317 >HAL_THREAD_LOAD_CONTEXT()</TT
318 >
319 loads a thread context, destroying the current context. With a little
320 care this can be implemented by sharing code with
321 <TT
322 CLASS="FUNCTION"
323 >HAL_THREAD_SWITCH_CONTEXT()</TT
324 >. To load a thread
325 context simply requires the saved registers to be restored from the
326 stack and a jump or return made back to the saved PC.</P
327 ><P
328 >Note that interrupts are not disabled during this process, any
329 interrupts that occur will be delivered onto the stack to which the
330 current CPU stack pointer points. Hence the stack pointer
331 should never be invalid, or loaded with a value that might cause the
332 saved state to become corrupted by an interrupt. However, the current
333 interrupt state is saved and restored as part of the thread
334 context. If a thread disables interrupts and does something to cause a
335 context switch, interrupts may be re-enabled on switching to another
336 thread. Interrupts will be disabled again when the original thread
337 regains control.</P
338 ></DIV
339 ><DIV
340 CLASS="SECTION"
341 ><H2
342 CLASS="SECTION"
343 ><A
344 NAME="AEN7842">Bit indexing</H2
345 ><TABLE
346 BORDER="5"
347 BGCOLOR="#E0E0F0"
348 WIDTH="70%"
349 ><TR
350 ><TD
351 ><PRE
352 CLASS="PROGRAMLISTING"
353 >HAL_LSBIT_INDEX( index, mask )
354 HAL_MSBIT_INDEX( index, mask )</PRE
355 ></TD
356 ></TR
357 ></TABLE
358 ><P
359 >These macros place in <TT
360 CLASS="PARAMETER"
361 ><I
362 >index</I
363 ></TT
364 > the bit index of
365 the least significant bit in <TT
366 CLASS="PARAMETER"
367 ><I
368 >mask</I
369 ></TT
370 >. Some
371 architectures have instruction level support for one or other of these
372 operations. If no architectural support is available, then these
373 macros may call C functions to do the job.</P
374 ></DIV
375 ><DIV
376 CLASS="SECTION"
377 ><H2
378 CLASS="SECTION"
379 ><A
380 NAME="AEN7848">Idle thread activity</H2
381 ><TABLE
382 BORDER="5"
383 BGCOLOR="#E0E0F0"
384 WIDTH="70%"
385 ><TR
386 ><TD
387 ><PRE
388 CLASS="PROGRAMLISTING"
389 >HAL_IDLE_THREAD_ACTION( count )</PRE
390 ></TD
391 ></TR
392 ></TABLE
393 ><P
394 >It may be necessary under some circumstances for the HAL to execute
395 code in the kernel idle thread's loop. An example might be to execute
396 a processor halt instruction. This macro provides a portable way of
397 doing this. The argument is a copy of the idle thread's loop counter,
398 and may be used to trigger actions at longer intervals than every
399 loop.</P
400 ></DIV
401 ><DIV
402 CLASS="SECTION"
403 ><H2
404 CLASS="SECTION"
405 ><A
406 NAME="AEN7852">Reorder barrier</H2
407 ><TABLE
408 BORDER="5"
409 BGCOLOR="#E0E0F0"
410 WIDTH="70%"
411 ><TR
412 ><TD
413 ><PRE
414 CLASS="PROGRAMLISTING"
415 >HAL_REORDER_BARRIER()</PRE
416 ></TD
417 ></TR
418 ></TABLE
419 ><P
420 >When optimizing the compiler can reorder code. In some parts of
421 multi-threaded systems, where the order of actions is vital, this can
422 sometimes cause problems. This macro may be inserted into places where
423 reordering should not happen and prevents code being migrated across
424 it by the compiler optimizer. It should be placed between statements
425 that must be executed in the order written in the code.</P
426 ></DIV
427 ><DIV
428 CLASS="SECTION"
429 ><H2
430 CLASS="SECTION"
431 ><A
432 NAME="AEN7856">Breakpoint support</H2
433 ><TABLE
434 BORDER="5"
435 BGCOLOR="#E0E0F0"
436 WIDTH="70%"
437 ><TR
438 ><TD
439 ><PRE
440 CLASS="PROGRAMLISTING"
441 >HAL_BREAKPOINT( label )
442 HAL_BREAKINST
443 HAL_BREAKINST_SIZE</PRE
444 ></TD
445 ></TR
446 ></TABLE
447 ><P
448 >These macros provide support for breakpoints.</P
449 ><P
450 ><TT
451 CLASS="FUNCTION"
452 >HAL_BREAKPOINT()</TT
453 > executes a breakpoint
454 instruction. The label is defined at the breakpoint instruction so
455 that exception code can detect which breakpoint was executed.</P
456 ><P
457 ><TT
458 CLASS="LITERAL"
459 >HAL_BREAKINST</TT
460 > contains the breakpoint instruction
461 code as an integer value. <TT
462 CLASS="LITERAL"
463 >HAL_BREAKINST_SIZE</TT
464 > is
465 the size of that breakpoint instruction in bytes. Together these
466 may be used to place a breakpoint in any code.</P
467 ></DIV
468 ><DIV
469 CLASS="SECTION"
470 ><H2
471 CLASS="SECTION"
472 ><A
473 NAME="AEN7865">GDB support</H2
474 ><TABLE
475 BORDER="5"
476 BGCOLOR="#E0E0F0"
477 WIDTH="70%"
478 ><TR
479 ><TD
480 ><PRE
481 CLASS="PROGRAMLISTING"
482 >HAL_THREAD_GET_SAVED_REGISTERS( sp, regs )
483 HAL_GET_GDB_REGISTERS( regval, regs )
484 HAL_SET_GDB_REGISTERS( regs, regval )</PRE
485 ></TD
486 ></TR
487 ></TABLE
488 ><P
489 >These macros provide support for interfacing GDB to the HAL.</P
490 ><P
491 ><TT
492 CLASS="FUNCTION"
493 >HAL_THREAD_GET_SAVED_REGISTERS()</TT
494 > extracts a
495 pointer to a <SPAN
496 CLASS="STRUCTNAME"
497 >HAL_SavedRegisters</SPAN
498 > structure
499 from a stack pointer value. The stack pointer passed in should be the
500 value saved by the thread context macros. The macro will assign a
501 pointer to the <SPAN
502 CLASS="STRUCTNAME"
503 >HAL_SavedRegisters</SPAN
504 > structure
505 to the variable passed as the second argument.</P
506 ><P
507 ><TT
508 CLASS="FUNCTION"
509 >HAL_GET_GDB_REGISTERS()</TT
510 > translates a register
511 state as saved by the HAL and into a register dump in the format
512 expected by GDB. It takes a pointer to a
513 <SPAN
514 CLASS="STRUCTNAME"
515 >HAL_SavedRegisters</SPAN
516 > structure in the
517 <TT
518 CLASS="PARAMETER"
519 ><I
520 >regs</I
521 ></TT
522 > argument and a pointer to the memory to
523 contain the GDB register dump in the <TT
524 CLASS="PARAMETER"
525 ><I
526 >regval</I
527 ></TT
528 >
529 argument.</P
530 ><P
531 ><TT
532 CLASS="FUNCTION"
533 >HAL_SET_GDB_REGISTERS()</TT
534 > translates a GDB format
535 register dump into a the format expected by the HAL.  It takes a
536 pointer to the memory containing the GDB register dump in the
537 <TT
538 CLASS="PARAMETER"
539 ><I
540 >regval</I
541 ></TT
542 > argument and a pointer to a
543 <SPAN
544 CLASS="STRUCTNAME"
545 >HAL_SavedRegisters</SPAN
546 > structure
547 in the <TT
548 CLASS="PARAMETER"
549 ><I
550 >regs</I
551 ></TT
552 > argument.</P
553 ></DIV
554 ><DIV
555 CLASS="SECTION"
556 ><H2
557 CLASS="SECTION"
558 ><A
559 NAME="AEN7883">Setjmp and longjmp support</H2
560 ><TABLE
561 BORDER="5"
562 BGCOLOR="#E0E0F0"
563 WIDTH="70%"
564 ><TR
565 ><TD
566 ><PRE
567 CLASS="PROGRAMLISTING"
568 >CYGARC_JMP_BUF_SIZE
569 hal_jmp_buf[CYGARC_JMP_BUF_SIZE]
570 hal_setjmp( hal_jmp_buf env )
571 hal_longjmp( hal_jmp_buf env, int val )</PRE
572 ></TD
573 ></TR
574 ></TABLE
575 ><P
576 >These functions provide support for the C
577 <TT
578 CLASS="FUNCTION"
579 >setjmp()</TT
580 > and <TT
581 CLASS="FUNCTION"
582 >longjmp()</TT
583 >
584 functions.  Refer to the C library for further information.</P
585 ></DIV
586 ><DIV
587 CLASS="SECTION"
588 ><H2
589 CLASS="SECTION"
590 ><A
591 NAME="AEN7889">Stack Sizes</H2
592 ><TABLE
593 BORDER="5"
594 BGCOLOR="#E0E0F0"
595 WIDTH="70%"
596 ><TR
597 ><TD
598 ><PRE
599 CLASS="PROGRAMLISTING"
600 >CYGNUM_HAL_STACK_SIZE_MINIMUM
601 CYGNUM_HAL_STACK_SIZE_TYPICAL</PRE
602 ></TD
603 ></TR
604 ></TABLE
605 ><P
606 >The values of these macros define the minimum and typical sizes of
607 thread stacks.</P
608 ><P
609 ><TT
610 CLASS="LITERAL"
611 >CYGNUM_HAL_STACK_SIZE_MINIMUM</TT
612 > defines the minimum
613 size of a thread stack. This is enough for the thread to function
614 correctly within eCos and allows it to take interrupts and context
615 switches. There should also be enough space for a simple thread entry
616 function to execute and call basic kernel operations on objects like
617 mutexes and semaphores. However there will not be enough room for much
618 more than this. When creating stacks for their own threads,
619 applications should determine the stack usage needed for application
620 purposes and then add
621 <TT
622 CLASS="LITERAL"
623 >CYGNUM_HAL_STACK_SIZE_MINIMUM</TT
624 >.</P
625 ><P
626 ><TT
627 CLASS="LITERAL"
628 >CYGNUM_HAL_STACK_SIZE_TYPICAL</TT
629 > is a reasonable increment over
630 <TT
631 CLASS="LITERAL"
632 >CYGNUM_HAL_STACK_SIZE_MINIMUM</TT
633 >, usually about 1kB. This should be
634 adequate for most modest thread needs. Only threads that need to
635 define significant amounts of local data, or have very deep call trees
636 should need to use a larger stack size.</P
637 ></DIV
638 ><DIV
639 CLASS="SECTION"
640 ><H2
641 CLASS="SECTION"
642 ><A
643 NAME="AEN7899">Address Translation</H2
644 ><TABLE
645 BORDER="5"
646 BGCOLOR="#E0E0F0"
647 WIDTH="70%"
648 ><TR
649 ><TD
650 ><PRE
651 CLASS="PROGRAMLISTING"
652 >CYGARC_CACHED_ADDRESS(addr)
653 CYGARC_UNCACHED_ADDRESS(addr)
654 CYGARC_PHYSICAL_ADDRESS(addr)</PRE
655 ></TD
656 ></TR
657 ></TABLE
658 ><P
659 >These macros provide address translation between different views of
660 memory. In many architectures a given memory location may be visible
661 at different addresses in both cached and uncached forms. It is also
662 possible that the MMU or some other address translation unit in the
663 CPU presents memory to the program at a different virtual address to
664 its physical address on the bus.</P
665 ><P
666 ><TT
667 CLASS="FUNCTION"
668 >CYGARC_CACHED_ADDRESS()</TT
669 > translates the given
670 address to its location in cached memory. This is typically where the
671 application will access the memory.</P
672 ><P
673 ><TT
674 CLASS="FUNCTION"
675 >CYGARC_UNCACHED_ADDRESS()</TT
676 > translates the given
677 address to its location in uncached memory. This is typically where
678 device drivers will access the memory to avoid cache problems. It may
679 additionally be necessary for the cache to be flushed before the
680 contents of this location is fully valid.</P
681 ><P
682 ><TT
683 CLASS="FUNCTION"
684 >CYGARC_PHYSICAL_ADDRESS()</TT
685 > translates the given
686 address to its location in the physical address space. This is
687 typically the address that needs to be passed to device hardware such
688 as a DMA engine, ethernet device or PCI bus bridge. The physical
689 address may not be directly accessible to the program, it may be
690 re-mapped by address translation.</P
691 ></DIV
692 ><DIV
693 CLASS="SECTION"
694 ><H2
695 CLASS="SECTION"
696 ><A
697 NAME="AEN7909">Global Pointer</H2
698 ><TABLE
699 BORDER="5"
700 BGCOLOR="#E0E0F0"
701 WIDTH="70%"
702 ><TR
703 ><TD
704 ><PRE
705 CLASS="PROGRAMLISTING"
706 >CYGARC_HAL_SAVE_GP()
707 CYGARC_HAL_RESTORE_GP()</PRE
708 ></TD
709 ></TR
710 ></TABLE
711 ><P
712 >These macros insert code to save and restore any global data pointer
713 that the ABI uses. These are necessary when switching context between
714 two eCos instances - for example between an eCos application and
715 RedBoot.</P
716 ></DIV
717 ></DIV
718 ><DIV
719 CLASS="NAVFOOTER"
720 ><HR
721 ALIGN="LEFT"
722 WIDTH="100%"><TABLE
723 SUMMARY="Footer navigation table"
724 WIDTH="100%"
725 BORDER="0"
726 CELLPADDING="0"
727 CELLSPACING="0"
728 ><TR
729 ><TD
730 WIDTH="33%"
731 ALIGN="left"
732 VALIGN="top"
733 ><A
734 HREF="hal-interfaces.html"
735 ACCESSKEY="P"
736 >Prev</A
737 ></TD
738 ><TD
739 WIDTH="34%"
740 ALIGN="center"
741 VALIGN="top"
742 ><A
743 HREF="ecos-ref.html"
744 ACCESSKEY="H"
745 >Home</A
746 ></TD
747 ><TD
748 WIDTH="33%"
749 ALIGN="right"
750 VALIGN="top"
751 ><A
752 HREF="hal-interrupt-handling.html"
753 ACCESSKEY="N"
754 >Next</A
755 ></TD
756 ></TR
757 ><TR
758 ><TD
759 WIDTH="33%"
760 ALIGN="left"
761 VALIGN="top"
762 >HAL Interfaces</TD
763 ><TD
764 WIDTH="34%"
765 ALIGN="center"
766 VALIGN="top"
767 ><A
768 HREF="hal-interfaces.html"
769 ACCESSKEY="U"
770 >Up</A
771 ></TD
772 ><TD
773 WIDTH="33%"
774 ALIGN="right"
775 VALIGN="top"
776 >Interrupt Handling</TD
777 ></TR
778 ></TABLE
779 ></DIV
780 ></BODY
781 ></HTML
782 >