Changeset 0bb0b8d in rtems-docs for cpu-supplement
- Timestamp:
- Nov 9, 2018, 10:28:10 PM (2 years ago)
- Branches:
- 5, am, master
- Children:
- ae05a27
- Parents:
- f067ba3
- git-author:
- Joel Sherrill <joel@…> (11/09/18 22:28:10)
- git-committer:
- Joel Sherrill <joel@…> (11/19/18 19:11:52)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
cpu-supplement/sparc_v8_stacks_regwin.rst
rf067ba3 r0bb0b8d 1 1 .. comment SPDX-License-Identifier: CC-BY-SA-4.0 2 2 3 .. COMMENT: Permission granted by the original author (Peter Magnusson) to 4 .. COMMENT: convert this page to Rest and include in the RTEMS Documentation. 5 .. COMMENT: This content is no longer online and only accessible at 6 .. COMMENT: https://web.archive.org/web/20120205014832/https://www.sics.se/~psm/sparcstack.html 7 8 Understanding stacks and registers in the Sparc architecture(s) 3 .. comment Permission granted by the original author (Peter Magnusson) to 4 .. comment convert this page to Rest and include in the RTEMS Documentation. 5 .. comment This content is no longer online and only accessible at 6 .. comment https://web.archive.org/web/20120205014832/https://www.sics.se/~psm/sparcstack.html 7 8 .. comment XXX Format Tables 9 .. comment XXX Format Figures (could be code, ascii art, etc.) 10 .. comment XXX double check against web page 11 .. comment XXX Fix Figure references in text 12 .. comment XXX instruction names probably should be marked as code font 13 14 Understanding stacks and registers in the SPARC architecture(s) 9 15 =============================================================== 10 The Sparc architecture from Sun Microsystems has some "interesting" characteristics. After having to deal with both compiler, interpreter, OS emulator, and OS porting issues for the Sparc, I decided to gather notes and documentation in one place. If there are any issues you don't find addressed by this page, or if you know of any similar Net resources, let me know. This document is limited to the V8 version of the architecture. 16 The SPARC architecture from Sun Microsystems has some "interesting" 17 characteristics. After having to deal with both compiler, interpreter, OS 18 emulator, and OS porting issues for the SPARC, I decided to gather notes 19 and documentation in one place. If there are any issues you don't find 20 addressed by this page, or if you know of any similar Net resources, let 21 me know. This document is limited to the V8 version of the architecture. 11 22 12 23 General Structure 13 Sparc has 32 general purpose integer registers visible to the program at any given time. Of these, 8 registers are global registers and 24 registers are in a register window. A window consists of three groups of 8 registers, the out, local, and in registers. See table 1. A Sparc implementation can have from 2 to 32 windows, thus varying the number of registers from 40 to 520. Most implentations have 7 or 8 windows. The variable number of registers is the principal reason for the Sparc being "scalable". 14 15 At any given time, only one window is visible, as determined by the current window pointer (CWP) which is part of the processor status register (PSR). This is a five bit value that can be decremented or incremented by the SAVE and RESTORE instructions, respectively. These instructions are generally executed on procedure call and return (respectively). The idea is that the in registers contain incoming parameters, the local register constitute scratch registers, the out registers contain outgoing parameters, and the global registers contain values that vary little between executions. The register windows overlap partially, thus the out registers become renamed by SAVE to become the in registers of the called procedure. Thus, the memory traffic is reduced when going up and down the procedure call. Since this is a frequent operation, performance is improved. 16 17 (That was the idea, anyway. The drawback is that upon interactions with the system the registers need to be flushed to the stack, necessitating a long sequence of writes to memory of data that is often mostly garbage. Register windows was a bad idea that was caused by simulation studies that considered only programs in isolation, as opposed to multitasking workloads, and by considering compilers with poor optimization. It also caused considerable problems in implementing high-end Sparc processors such as the SuperSparc, although more recent implementations have dealt effectively with the obstacles. Register windows is now part of the compatibility legacy and not easily removed from the architecture.) 18 19 Register Group Mnemonic Register Address 20 global %g0-%g7 r[0]-r[7] 21 out %o0-%o7 r[8]-r[15] 22 local %l0-%l7 r[16]-r[23] 23 in %i0-%i7 r[24]-r[31] 24 ----------------- 25 SPARC has 32 general purpose integer registers visible to the program 26 at any given time. Of these, 8 registers are global registers and 24 27 registers are in a register window. A window consists of three groups 28 of 8 registers, the out, local, and in registers. See table 1. A SPARC 29 implementation can have from 2 to 32 windows, thus varying the number 30 of registers from 40 to 520. Most implentations have 7 or 8 windows. The 31 variable number of registers is the principal reason for the SPARC being 32 "scalable". 33 34 At any given time, only one window is visible, as determined by the 35 current window pointer (CWP) which is part of the processor status 36 register (PSR). This is a five bit value that can be decremented or 37 incremented by the SAVE and RESTORE instructions, respectively. These 38 instructions are generally executed on procedure call and return 39 (respectively). The idea is that the in registers contain incoming 40 parameters, the local register constitute scratch registers, the out 41 registers contain outgoing parameters, and the global registers contain 42 values that vary little between executions. The register windows overlap 43 partially, thus the out registers become renamed by SAVE to become the in 44 registers of the called procedure. Thus, the memory traffic is reduced 45 when going up and down the procedure call. Since this is a frequent 46 operation, performance is improved. 47 48 (That was the idea, anyway. The drawback is that upon interactions 49 with the system the registers need to be flushed to the stack, 50 necessitating a long sequence of writes to memory of data that is 51 often mostly garbage. Register windows was a bad idea that was caused 52 by simulation studies that considered only programs in isolation, as 53 opposed to multitasking workloads, and by considering compilers with 54 poor optimization. It also caused considerable problems in implementing 55 high-end SPARC processors such as the SuperSPARC, although more recent 56 implementations have dealt effectively with the obstacles. Register 57 windows is now part of the compatibility legacy and not easily removed 58 from the architecture.) 59 60 .. comment XXX FIX FORMATTING 61 62 +------------+------------+---------------+ 63 | Register | Mnemonic | Register | 64 | Group | | Address | 65 +============+============+===============+ 66 + global + %g0-%g7 + r[0] - r[7] + 67 +------------+------------+---------------+ 68 + out + %o0-%o7 + r[8] - r[15] + 69 +------------+------------+---------------+ 70 + local + %l0-%l7 + r[16] - r[23] + 71 +------------+------------+---------------+ 72 + in + %i0-%i7 + r[24] - r[31] + 73 +------------+------------+---------------+ 24 74 25 75 Table 1 - Visible Registers 26 76 27 The overlap of the registers is illustrated in figure 1. The figure shows an implementation with 8 windows, numbered 0 to 7 (labeled w0 to w7 in the figure).. Each window corresponds to 24 registers, 16 of which are shared with "neighboring" windows. The windows are arranged in a wrap-around manner, thus window number 0 borders window number 7. The common cause of changing the current window, as pointed to by CWP, is the RESTORE and SAVE instuctions, shown in the middle. Less common is the supervisor RETT instruction (return from trap) and the trap event (interrupt, exception, or TRAP instruction). 77 The overlap of the registers is illustrated in figure 1. The figure 78 shows an implementation with 8 windows, numbered 0 to 7 (labeled w0 to 79 w7 in the figure).. Each window corresponds to 24 registers, 16 of which 80 are shared with "neighboring" windows. The windows are arranged in a 81 wrap-around manner, thus window number 0 borders window number 7. The 82 common cause of changing the current window, as pointed to by CWP, is 83 the RESTORE and SAVE instuctions, shown in the middle. Less common is 84 the supervisor RETT instruction (return from trap) and the trap event 85 (interrupt, exception, or TRAP instruction). 86 87 .. comment XXX insert graphic from website (redraw if needed) 28 88 29 89 Figure 1 - Windowed Registers 30 90 31 The "WIM" register is also indicated in the top left of figure 1. The window invalid mask is a bit map of valid windows. It is generally used as a pointer, i.e. exactly one bit is set in the WIM register indicating which window is invalid (in the figure it's window 7). Register windows are generally used to support procedure calls, so they can be viewed as a cache of the stack contents. The WIM "pointer" indicates how many procedure calls in a row can be taken without writing out data to memory. In the figure, the capacity of the register windows is fully utilized. An additional call will thus exceed capacity, triggering a window overflow trap. At the other end, a window underflow trap occurs when the register window "cache" if empty and more data needs to be fetched from memory. 91 The "WIM" register is also indicated in the top left of Figure 1. The 92 window invalid mask is a bit map of valid windows. It is generally used 93 as a pointer, i.e. exactly one bit is set in the WIM register indicating 94 which window is invalid (in the figure it's window 7). Register windows 95 are generally used to support procedure calls, so they can be viewed 96 as a cache of the stack contents. The WIM "pointer" indicates how 97 many procedure calls in a row can be taken without writing out data to 98 memory. In the figure, the capacity of the register windows is fully 99 utilized. An additional call will thus exceed capacity, triggering a 100 window overflow trap. At the other end, a window underflow trap occurs 101 when the register window "cache" if empty and more data needs to be 102 fetched from memory. 32 103 33 104 Register Semantics 34 The Sparc Architecture includes recommended software semantics. These are described in the architecture manual, the Sparc ABI (application binary interface) standard, and, unfortunately, in various other locations as well (including header files and compiler documentation). 105 ------------------ 106 107 The SPARC Architecture includes recommended software semantics. These are 108 described in the architecture manual, the SPARC ABI (application binary 109 interface) standard, and, unfortunately, in various other locations as 110 well (including header files and compiler documentation). 35 111 36 112 Figure 2 shows a summary of register contents at any given time. 113 114 .. comment XXX FIX FORMATTING 115 116 .. code-block:: c 37 117 38 118 %g0 (r00) always zero … … 78 158 [3] assumed by caller to be preserved across a procedure call 79 159 80 Figure 2 - S parcregister semantics160 Figure 2 - SPARC register semantics 81 161 82 162 Particular compilers are likely to vary slightly. 83 163 84 Note that globals %g2-%g4 are reserved for the "application", which includes libraries and compiler. Thus, for example, libraries may overwrite these registers unless they've been compiled with suitable flags. Also, the "reserved" registers are presumed to be allocated (in the future) bottom-up, i.e. %g7 is currently the "safest" to use. 164 Note that globals %g2-%g4 are reserved for the "application", which 165 includes libraries and compiler. Thus, for example, libraries may 166 overwrite these registers unless they've been compiled with suitable 167 flags. Also, the "reserved" registers are presumed to be allocated 168 (in the future) bottom-up, i.e. %g7 is currently the "safest" to use. 85 169 86 170 Optimizing linkers and interpreters are exmples that use global registers. 87 171 88 172 Register Windows and the Stack 89 The sparc register windows are, naturally, intimately related to the stack. In particular, the stack pointer (%sp or %o6) must always point to a free block of 64 bytes. This area is used by the operating system (Solaris, SunOS, and Linux at least) to save the current local and in registers upon a system interupt, exception, or trap instruction. (Note that this can occur at any time.) 90 91 Other aspects of register relations with memory are programming convention. The typical, and recommended, layout of the stack is shown in figure 3. The figure shows a stack frame. 173 ------------------------------ 174 175 The SPARC register windows are, naturally, intimately related to the 176 stack. In particular, the stack pointer (%sp or %o6) must always point 177 to a free block of 64 bytes. This area is used by the operating system 178 (Solaris, SunOS, and Linux at least) to save the current local and in 179 registers upon a system interupt, exception, or trap instruction. (Note 180 that this can occur at any time.) 181 182 Other aspects of register relations with memory are programming 183 convention. The typical, and recommended, layout of the stack is shown 184 in figure 3. The figure shows a stack frame. 185 186 .. comment XXX FIX FORMATTING 187 188 .. code-block:: c 92 189 93 190 low addresses … … 129 226 Figure 3 - Stack frame contents 130 227 131 Note that the top boxes of figure 3 are addressed via the stack pointer (%sp), as positive offsets (including zero), and the bottom boxes are accessed over the frame pointer using negative offsets (excluding zero), and that the frame pointer is the old stack pointer. This scheme allows the separation of information known at compile time (number and size of local parameters, etc) from run-time information (size of blocks allocated by alloca()). 228 Note that the top boxes of figure 3 are addressed via the stack pointer 229 (%sp), as positive offsets (including zero), and the bottom boxes are 230 accessed over the frame pointer using negative offsets (excluding zero), 231 and that the frame pointer is the old stack pointer. This scheme allows 232 the separation of information known at compile time (number and size 233 of local parameters, etc) from run-time information (size of blocks 234 allocated by alloca()). 132 235 133 236 "addressable scalar automatics" is a fancy name for local variables. 134 237 135 The clever nature of the stack and frame pointers are that they are always 16 registers apart in the register windows. Thus, a SAVE instruction will make the current stack pointer into the frame pointer and, since the SAVE instruction also doubles as an ADD, create a new stack pointer. Figure 4 illustrates what the top of a stack might look like during execution. (The listing is from the "pwin" command in the SimICS simulator.) 238 The clever nature of the stack and frame pointers are that they are always 239 16 registers apart in the register windows. Thus, a SAVE instruction will 240 make the current stack pointer into the frame pointer and, since the SAVE 241 instruction also doubles as an ADD, create a new stack pointer. Figure 4 242 illustrates what the top of a stack might look like during execution. (The 243 listing is from the "pwin" command in the SimICS simulator.) 244 245 .. comment XXX FIX FORMATTING 246 247 .. code-block:: c 136 248 137 249 REGISTER WINDOWS … … 215 327 Figure 4 - Sample stack contents 216 328 217 Note how the stack contents are not necessarily synchronized with the registers. Various events can cause the register windows to be "flushed" to memory, including most system calls. A programmer can force this update by using ST_FLUSH_WINDOWS trap, which also reduces the number of valid windows to the minimum of 1. 218 219 Writing a library for multithreaded execution is an example that requires explicit flushing, as is longjmp(). 329 Note how the stack contents are not necessarily synchronized with the 330 registers. Various events can cause the register windows to be "flushed" 331 to memory, including most system calls. A programmer can force this 332 update by using ST_FLUSH_WINDOWS trap, which also reduces the number of 333 valid windows to the minimum of 1. 334 335 Writing a library for multithreaded execution is an example that requires 336 explicit flushing, as is longjmp(). 220 337 221 338 Procedure epilogue and prologue 222 The stack frame described in the previous section leads to the standard entry/exit mechanisms listed in figure 5. 339 ------------------------------- 340 341 The stack frame described in the previous section leads to the standard 342 entry/exit mechanisms listed in figure 5. 343 344 .. comment XXX FIX FORMATTING 345 346 .. code-block:: c 223 347 224 348 function: … … 233 357 Figure 5 - Epilogue/prologue in procedures 234 358 235 The SAVE instruction decrements the CWP, as discussed earlier, and also performs an addition. The constant "C" that is used in the figure to indicate the amount of space to make on the stack, and thus corresponds to the frame contents in Figure 3. The minimum is therefore the 16 words for the LOCAL and IN registers, i.e. (hex) 0x40 bytes. 236 237 A confusing element of the SAVE instruction is that the source operands (the first two parameters) are read from the old register window, and the destination operand (the rightmost parameter) is written to the new window. Thus, allthough "%sp" is indicated as both source and destination, the result is actually written into the stack pointer of the new window (the source stack pointer becomes renamed and is now the frame pointer). 238 239 The return instructions are also a bit particular. ret is a synthetic instruction, corresponding to jmpl (jump linked). This instruction jumps to the address resulting from adding 8 to the %i7 register. The source instruction address (the address of the ret instruction itself) is written to the %g0 register, i.e. it is discarded. 240 241 The restore instruction is similarly a synthetic instruction, and is just a short form for a restore that choses not to perform an addition. 359 The SAVE instruction decrements the CWP, as discussed earlier, and also 360 performs an addition. The constant "C" that is used in the figure to 361 indicate the amount of space to make on the stack, and thus corresponds 362 to the frame contents in Figure 3. The minimum is therefore the 16 words 363 for the LOCAL and IN registers, i.e. (hex) 0x40 bytes. 364 365 A confusing element of the SAVE instruction is that the source operands 366 (the first two parameters) are read from the old register window, and 367 the destination operand (the rightmost parameter) is written to the new 368 window. Thus, allthough "%sp" is indicated as both source and destination, 369 the result is actually written into the stack pointer of the new window 370 (the source stack pointer becomes renamed and is now the frame pointer). 371 372 The return instructions are also a bit particular. ret is a synthetic 373 instruction, corresponding to jmpl (jump linked). This instruction 374 jumps to the address resulting from adding 8 to the %i7 register. The 375 source instruction address (the address of the ret instruction itself) 376 is written to the %g0 register, i.e. it is discarded. 377 378 The restore instruction is similarly a synthetic instruction, and is 379 just a short form for a restore that choses not to perform an addition. 242 380 243 381 The calling instruction, in turn, typically looks as follows: 382 383 .. comment XXX FIX FORMATTING 384 385 .. code-block:: c 244 386 245 387 call <function> ; jmpl <address>, %o7 246 388 mov 0, %o0 247 389 248 Again, the call instruction is synthetic, and is actually the same instruction that performs the return. This time, however, it is interested in saving the return address, into register %o7. Note that the delay slot is often filled with an instruction related to the parameters, in this example it sets the first parameter to zero. 390 Again, the call instruction is synthetic, and is actually the same 391 instruction that performs the return. This time, however, it is interested 392 in saving the return address, into register %o7. Note that the delay 393 slot is often filled with an instruction related to the parameters, 394 in this example it sets the first parameter to zero. 249 395 250 396 Note also that the return value is also generally passed in %o0. 251 397 252 Leaf procedures are different. A leaf procedure is an optimization that reduces unnecessary work by taking advantage of the knowledge that no call instructions exist in many procedures. Thus, the save/restore couple can be eliminated. The downside is that such a procedure may only use the out registers (since the in and local registers actually belong to the caller). See Figure 6. 398 Leaf procedures are different. A leaf procedure is an optimization that 399 reduces unnecessary work by taking advantage of the knowledge that no 400 call instructions exist in many procedures. Thus, the save/restore couple 401 can be eliminated. The downside is that such a procedure may only use 402 the out registers (since the in and local registers actually belong to 403 the caller). See Figure 6. 404 405 .. comment XXX FIX FORMATTING 406 407 .. code-block:: c 253 408 254 409 function: … … 263 418 Figure 6 - Epilogue/prologue in leaf procedures 264 419 265 Note in the figure that there is only one instruction overhead, namely the retl instruction. retl is also synthetic (return from leaf subroutine), is again a variant of the jmpl instruction, this time with %o7+8 as target. 266 267 Yet another variation of epilogue is caused by tail call elimination, an optimization supported by some compilers (including Sun's C compiler but not GCC). If the compiler detects that a called function will return to the calling function, it can replace its place on the stack with the called function. Figure 7 contains an example. 420 Note in the figure that there is only one instruction overhead, namely the 421 retl instruction. retl is also synthetic (return from leaf subroutine), is 422 again a variant of the jmpl instruction, this time with %o7+8 as target. 423 424 Yet another variation of epilogue is caused by tail call elimination, 425 an optimization supported by some compilers (including Sun's C compiler 426 but not GCC). If the compiler detects that a called function will return 427 to the calling function, it can replace its place on the stack with the 428 called function. Figure 7 contains an example. 429 430 .. comment XXX FIX FORMATTING 431 432 .. code-block:: c 268 433 269 434 int … … 286 451 Figure 7 - Example of tail call elimination 287 452 288 Note that the call instruction overwrites register %o7 with the program counter. Therefore the above code saves the old value of %o7, and restores it in the delay slot of the call instruction. If the function call is register indirect, this twiddling with %o7 can be avoided, but of course that form of call is slower on modern processors. 289 290 The benefit of tail call elimination is to remove an indirection upon return. It is also needed to reduce register window usage, since otherwise the foo() function in Figure 7 would need to allocate a stack frame to save the program counter. 291 292 A special form of tail call elimination is tail recursion elimination, which detects functions calling themselves, and replaces it with a simple branch. Figure 8 contains an example. 453 Note that the call instruction overwrites register %o7 with the program 454 counter. Therefore the above code saves the old value of %o7, and restores 455 it in the delay slot of the call instruction. If the function call is 456 register indirect, this twiddling with %o7 can be avoided, but of course 457 that form of call is slower on modern processors. 458 459 The benefit of tail call elimination is to remove an indirection upon 460 return. It is also needed to reduce register window usage, since otherwise 461 the foo() function in Figure 7 would need to allocate a stack frame to 462 save the program counter. 463 464 A special form of tail call elimination is tail recursion elimination, 465 which detects functions calling themselves, and replaces it with a simple 466 branch. Figure 8 contains an example. 467 468 .. comment XXX FIX FORMATTING 469 470 .. code-block:: c 293 471 294 472 int … … 312 490 Figure 8 - Example of tail recursion elimination 313 491 314 Needless to say, these optimizations produce code that is difficult to debug. 492 Needless to say, these optimizations produce code that is difficult 493 to debug. 315 494 316 495 Procedures, stacks, and debuggers 317 When debugging an application, your debugger will be parsing the binary and consulting the symbol table to determine procedure entry points. It will also travel the stack frames "upward" to determine the current call chain. 318 319 When compiling for debugging, compilers will generate additional code as well as avoid some optimizations in order to allow reconstructing situations during execution. For example, GCC/GDB makes sure original parameter values are kept intact somewhere for future parsing of the procedure call stack. The live in registers other than %i0 are not touched. %i0 itself is copied into a free local register, and its location is noted in the symbol file. (You can find out where variables reside by using the "info address" command in GDB.) 320 321 Given that much of the semantics relating to stack handling and procedure call entry/exit code is only recommended, debuggers will sometimes be fooled. For example, the decision as to wether or not the current procedure is a leaf one or not can be incorrect. In this case a spurious procedure will be inserted between the current procedure and it's "real" parent. Another example is when the application maintains its own implicit call hierarchy, such as jumping to function pointers. In this case the debugger can easily become totally confused. 496 --------------------------------- 497 498 When debugging an application, your debugger will be parsing the binary 499 and consulting the symbol table to determine procedure entry points. It 500 will also travel the stack frames "upward" to determine the current 501 call chain. 502 503 When compiling for debugging, compilers will generate additional code 504 as well as avoid some optimizations in order to allow reconstructing 505 situations during execution. For example, GCC/GDB makes sure original 506 parameter values are kept intact somewhere for future parsing of 507 the procedure call stack. The live in registers other than %i0 are 508 not touched. %i0 itself is copied into a free local register, and its 509 location is noted in the symbol file. (You can find out where variables 510 reside by using the "info address" command in GDB.) 511 512 Given that much of the semantics relating to stack handling and procedure 513 call entry/exit code is only recommended, debuggers will sometimes 514 be fooled. For example, the decision as to wether or not the current 515 procedure is a leaf one or not can be incorrect. In this case a spurious 516 procedure will be inserted between the current procedure and it's "real" 517 parent. Another example is when the application maintains its own implicit 518 call hierarchy, such as jumping to function pointers. In this case the 519 debugger can easily become totally confused. 322 520 323 521 The window overflow and underflow traps 324 When the SAVE instruction decrements the current window pointer (CWP) so that it coincides with the invalid window in the window invalid mask (WIM), a window overflow trap occurs. Conversely, when the RESTORE or RETT instructions increment the CWP to coincide with the invalid window, a window underflow trap occurs. 325 326 Either trap is handled by the operating system. Generally, data is written out to memory and/or read from memory, and the WIM register suitably altered. 327 328 The code in Figure 9 and Figure 10 below are bare-bones handlers for the two traps. The text is directly from the source code, and sort of works. (As far as I know, these are minimalistic handlers for Sparc V8). Note that there is no way to directly access window registers other than the current one, hence the code does additional save/restore instructions. It's pretty tricky to understand the code, but figure 1 should be of help. 522 --------------------------------------- 523 524 When the SAVE instruction decrements the current window pointer (CWP) 525 so that it coincides with the invalid window in the window invalid mask 526 (WIM), a window overflow trap occurs. Conversely, when the RESTORE or 527 RETT instructions increment the CWP to coincide with the invalid window, 528 a window underflow trap occurs. 529 530 Either trap is handled by the operating system. Generally, data is 531 written out to memory and/or read from memory, and the WIM register 532 suitably altered. 533 534 The code in Figure 9 and Figure 10 below are bare-bones handlers for 535 the two traps. The text is directly from the source code, and sort of 536 works. (As far as I know, these are minimalistic handlers for SPARC 537 V8). Note that there is no way to directly access window registers 538 other than the current one, hence the code does additional save/restore 539 instructions. It's pretty tricky to understand the code, but figure 1 540 should be of help. 541 542 .. comment XXX FIX FORMATTING 543 544 .. code-block:: c 329 545 330 546 /* a SAVE instruction caused a trap */ 331 window_overflow:547 window_overflow: 332 548 /* rotate WIM on bit right, we have 8 windows */ 333 549 mov %wim,%l3 … … 367 583 Figure 9 - window_underflow trap handler 368 584 585 586 .. code-block:: c 587 588 369 589 /* a RESTORE instruction caused a trap */ 370 window_underflow:590 window_underflow: 371 591 372 592 /* rotate WIM on bit LEFT, we have 8 windows */
Note: See TracChangeset
for help on using the changeset viewer.