source: rtems/c/src/exec/score/cpu/sparc/cpu_asm.s @ 16bae52

4.104.114.84.95
Last change on this file since 16bae52 was 16bae52, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 1, 1996 at 3:06:00 PM

added 3 nops following write to wim since a restore following it is
subject to causing unpredictable window underflow/overflows.

  • Property mode set to 100644
File size: 24.7 KB
Line 
1/*  cpu_asm.s
2 *
3 *  This file contains the basic algorithms for all assembly code used
4 *  in an specific CPU port of RTEMS.  These algorithms must be implemented
5 *  in assembly language.
6 *
7 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
8 *  On-Line Applications Research Corporation (OAR).
9 *  All rights assigned to U.S. Government, 1994.
10 *
11 *  This material may be reproduced by or for the U.S. Government pursuant
12 *  to the copyright license under the clause at DFARS 252.227-7013.  This
13 *  notice must appear in all copies of this file and its derivatives.
14 *
15 *  Ported to ERC32 implementation of the SPARC by On-Line Applications
16 *  Research Corporation (OAR) under contract to the European Space
17 *  Agency (ESA).
18 *
19 *  ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995. 
20 *  European Space Agency.
21 *
22 *  $Id$
23 */
24
25#include <asm.h>
26#include <rtems/score/cpu.h>
27
28#if (SPARC_HAS_FPU == 1)
29
30/*
31 *  void _CPU_Context_save_fp(
32 *    void **fp_context_ptr
33 *  )
34 *
35 *  This routine is responsible for saving the FP context
36 *  at *fp_context_ptr.  If the point to load the FP context
37 *  from is changed then the pointer is modified by this routine.
38 *
39 *  NOTE: See the README in this directory for information on the
40 *        management of the "EF" bit in the PSR.
41 */
42
43        .align 4
44        PUBLIC(_CPU_Context_save_fp)
45SYM(_CPU_Context_save_fp):
46        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
47
48        /*
49         *  The following enables the floating point unit.
50         */
51   
52        mov     %psr, %l0
53        sethi   %hi(SPARC_PSR_EF_MASK), %l1
54        or      %l1, %lo(SPARC_PSR_EF_MASK), %l1
55        or      %l0, %l1, %l0
56        mov     %l0, %psr                  ! **** ENABLE FLOAT ACCESS ****
57
58        ld      [%i0], %l0
59        std     %f0, [%l0 + FO_F1_OFFSET]
60        std     %f2, [%l0 + F2_F3_OFFSET]
61        std     %f4, [%l0 + F4_F5_OFFSET]
62        std     %f6, [%l0 + F6_F7_OFFSET]
63        std     %f8, [%l0 + F8_F9_OFFSET]
64        std     %f10, [%l0 + F1O_F11_OFFSET]
65        std     %f12, [%l0 + F12_F13_OFFSET]
66        std     %f14, [%l0 + F14_F15_OFFSET]
67        std     %f16, [%l0 + F16_F17_OFFSET]
68        std     %f18, [%l0 + F18_F19_OFFSET]
69        std     %f20, [%l0 + F2O_F21_OFFSET]
70        std     %f22, [%l0 + F22_F23_OFFSET]
71        std     %f24, [%l0 + F24_F25_OFFSET]
72        std     %f26, [%l0 + F26_F27_OFFSET]
73        std     %f28, [%l0 + F28_F29_OFFSET]
74        std     %f30, [%l0 + F3O_F31_OFFSET]
75        st      %fsr, [%l0 + FSR_OFFSET]
76        ret
77        restore
78
79/*
80 *  void _CPU_Context_restore_fp(
81 *    void **fp_context_ptr
82 *  )
83 *
84 *  This routine is responsible for restoring the FP context
85 *  at *fp_context_ptr.  If the point to load the FP context
86 *  from is changed then the pointer is modified by this routine.
87 *
88 *  NOTE: See the README in this directory for information on the
89 *        management of the "EF" bit in the PSR.
90 */
91
92        .align 4
93        PUBLIC(_CPU_Context_restore_fp)
94SYM(_CPU_Context_restore_fp):
95        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE , %sp
96
97        /*
98         *  The following enables the floating point unit.
99         */
100   
101        mov     %psr, %l0
102        sethi   %hi(SPARC_PSR_EF_MASK), %l1
103        or      %l1, %lo(SPARC_PSR_EF_MASK), %l1
104        or      %l0, %l1, %l0
105        mov     %l0, %psr                  ! **** ENABLE FLOAT ACCESS ****
106
107        ld      [%i0], %l0
108        ldd     [%l0 + FO_F1_OFFSET], %f0
109        ldd     [%l0 + F2_F3_OFFSET], %f2
110        ldd     [%l0 + F4_F5_OFFSET], %f4
111        ldd     [%l0 + F6_F7_OFFSET], %f6
112        ldd     [%l0 + F8_F9_OFFSET], %f8
113        ldd     [%l0 + F1O_F11_OFFSET], %f10
114        ldd     [%l0 + F12_F13_OFFSET], %f12
115        ldd     [%l0 + F14_F15_OFFSET], %f14
116        ldd     [%l0 + F16_F17_OFFSET], %f16
117        ldd     [%l0 + F18_F19_OFFSET], %f18
118        ldd     [%l0 + F2O_F21_OFFSET], %f20
119        ldd     [%l0 + F22_F23_OFFSET], %f22
120        ldd     [%l0 + F24_F25_OFFSET], %f24
121        ldd     [%l0 + F26_F27_OFFSET], %f26
122        ldd     [%l0 + F28_F29_OFFSET], %f28
123        ldd     [%l0 + F3O_F31_OFFSET], %f30
124        ld      [%l0 + FSR_OFFSET], %fsr
125        ret
126        restore
127
128#endif /* SPARC_HAS_FPU */
129
130/*
131 *  void _CPU_Context_switch(
132 *    Context_Control  *run,
133 *    Context_Control  *heir
134 *  )
135 *
136 *  This routine performs a normal non-FP context switch.
137 */
138
139        .align 4
140        PUBLIC(_CPU_Context_switch)
141SYM(_CPU_Context_switch):
142        ! skip g0
143        st      %g1, [%o0 + G1_OFFSET]       ! save the global registers
144        std     %g2, [%o0 + G2_OFFSET]
145        std     %g4, [%o0 + G4_OFFSET]
146        std     %g6, [%o0 + G6_OFFSET]
147
148        std     %l0, [%o0 + L0_OFFSET]       ! save the local registers
149        std     %l2, [%o0 + L2_OFFSET]
150        std     %l4, [%o0 + L4_OFFSET]
151        std     %l6, [%o0 + L6_OFFSET]
152
153        std     %i0, [%o0 + I0_OFFSET]       ! save the input registers
154        std     %i2, [%o0 + I2_OFFSET]
155        std     %i4, [%o0 + I4_OFFSET]
156        std     %i6, [%o0 + I6_FP_OFFSET]
157
158        std     %o0, [%o0 + O0_OFFSET]       ! save the output registers
159        std     %o2, [%o0 + O2_OFFSET]
160        std     %o4, [%o0 + O4_OFFSET]
161        std     %o6, [%o0 + O6_SP_OFFSET]
162
163        rd      %psr, %o2
164        st      %o2, [%o0 + PSR_OFFSET]      ! save status register
165
166        /*
167         *  This is entered from _CPU_Context_restore with:
168         *    o1 = context to restore
169         *    o2 = psr
170         */
171
172        PUBLIC(_CPU_Context_restore_heir)
173SYM(_CPU_Context_restore_heir):
174        /*
175         *  Flush all windows with valid contents except the current one.
176         *  In examining the set register windows, one may logically divide
177         *  the windows into sets (some of which may be empty) based on their
178         *  current status: 
179         *
180         *    + current (i.e. in use), 
181         *    + used (i.e. a restore would not trap)
182         *    + invalid (i.e. 1 in corresponding bit in WIM)
183         *    + unused
184         *
185         *  Either the used or unused set of windows may be empty.
186         *
187         *  NOTE: We assume only one bit is set in the WIM at a time.
188         *
189         *  Given a CWP of 5 and a WIM of 0x1, the registers are divided
190         *  into sets as follows:
191         *
192         *    + 0   - invalid
193         *    + 1-4 - unused
194         *    + 5   - current
195         *    + 6-7 - used
196         *
197         *  In this case, we only would save the used windows -- 6 and 7.
198         *
199         *   Traps are disabled for the same logical period as in a
200         *     flush all windows trap handler.
201         *   
202         *    Register Usage while saving the windows:
203         *      g1 = current PSR
204         *      g2 = current wim
205         *      g3 = CWP
206         *      g4 = wim scratch
207         *      g5 = scratch
208         */
209
210        ld      [%o1 + PSR_OFFSET], %g1       ! g1 = saved psr
211
212        and     %o2, SPARC_PSR_CWP_MASK, %g3  ! g3 = CWP
213                                              ! g1 = psr w/o cwp
214        andn    %g1, SPARC_PSR_ET_MASK | SPARC_PSR_CWP_MASK, %g1
215        or      %g1, %g3, %g1                 ! g1 = heirs psr
216        mov     %g1, %psr                     ! restore status register and
217                                              ! **** DISABLE TRAPS ****
218        mov     %wim, %g2                     ! g2 = wim
219        mov     1, %g4
220        sll     %g4, %g3, %g4                 ! g4 = WIM mask for CW invalid
221
222save_frame_loop:
223        sll     %g4, 1, %g5                   ! rotate the "wim" left 1
224        srl     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
225        or      %g4, %g5, %g4                 ! g4 = wim if we do one restore
226
227        /*
228         *  If a restore would not underflow, then continue.
229         */
230
231        andcc   %g4, %g2, %g0                 ! Any windows to flush?
232        bnz     done_flushing                 ! No, then continue
233        nop
234
235        restore                               ! back one window
236
237        /*
238         *  Now save the window just as if we overflowed to it.
239         */
240 
241        std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
242        std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
243        std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
244        std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
245 
246        std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
247        std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
248        std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
249        std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
250
251        ba      save_frame_loop
252        nop
253
254done_flushing:
255
256        add     %g3, 1, %g3                   ! calculate desired WIM
257        and     %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
258        mov     1, %g4
259        sll     %g4, %g3, %g4                 ! g4 = new WIM
260        mov     %g4, %wim
261
262        or      %g1, SPARC_PSR_ET_MASK, %g1
263        mov     %g1, %psr                     ! **** ENABLE TRAPS ****
264                                              !   and restore CWP
265        nop
266        nop
267        nop
268
269        ! skip g0
270        ld      [%o1 + G1_OFFSET], %g1        ! restore the global registers
271        ldd     [%o1 + G2_OFFSET], %g2
272        ldd     [%o1 + G4_OFFSET], %g4
273        ldd     [%o1 + G6_OFFSET], %g6
274
275        ldd     [%o1 + L0_OFFSET], %l0        ! restore the local registers
276        ldd     [%o1 + L2_OFFSET], %l2
277        ldd     [%o1 + L4_OFFSET], %l4
278        ldd     [%o1 + L6_OFFSET], %l6
279
280        ldd     [%o1 + I0_OFFSET], %i0        ! restore the output registers
281        ldd     [%o1 + I2_OFFSET], %i2
282        ldd     [%o1 + I4_OFFSET], %i4
283        ldd     [%o1 + I6_FP_OFFSET], %i6
284
285        ldd     [%o1 + O2_OFFSET], %o2        ! restore the output registers
286        ldd     [%o1 + O4_OFFSET], %o4
287        ldd     [%o1 + O6_SP_OFFSET], %o6
288        ! do o0/o1 last to avoid destroying heir context pointer
289        ldd     [%o1 + O0_OFFSET], %o0        ! overwrite heir pointer
290
291        jmp     %o7 + 8                       ! return
292        nop                                   ! delay slot
293
294/*
295 *  void _CPU_Context_restore(
296 *    Context_Control *new_context
297 *  )
298 *
299 *  This routine is generally used only to perform restart self.
300 *
301 *  NOTE: It is unnecessary to reload some registers.
302 */
303
304        .align 4
305        PUBLIC(_CPU_Context_restore)
306SYM(_CPU_Context_restore):
307        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
308        rd      %psr, %o2
309        ba      SYM(_CPU_Context_restore_heir)
310        mov     %i0, %o1                      ! in the delay slot
311
312/*
313 *  void _ISR_Handler()
314 *
315 *  This routine provides the RTEMS interrupt management.
316 *
317 *  We enter this handler from the 4 instructions in the trap table with
318 *  the following registers assumed to be set as shown:
319 *
320 *    l0 = PSR
321 *    l1 = PC
322 *    l2 = nPC
323 *    l3 = trap type
324 *
325 *  NOTE: By an executive defined convention, trap type is between 0 and 255 if
326 *        it is an asynchonous trap and 256 and 511 if it is synchronous.
327 */
328
329        .align 4
330        PUBLIC(_ISR_Handler)
331SYM(_ISR_Handler):
332        /*
333         *  Fix the return address for synchronous traps.
334         */
335
336        andcc   %l3, SPARC_SYNCHRONOUS_TRAP_BIT_MASK, %g0
337                                      ! Is this a synchronous trap?
338        be,a    win_ovflow            ! No, then skip the adjustment
339        nop                           ! DELAY
340        mov     %l2, %l1              ! do not return to the instruction
341        add     %l2, 4, %l2           ! indicated
342
343win_ovflow:
344        /*
345         *  Save the globals this block uses.
346         *
347         *  These registers are not restored from the locals.  Their contents
348         *  are saved directly from the locals into the ISF below.
349         */
350
351        mov     %g4, %l4                 ! save the globals this block uses
352        mov     %g5, %l5
353
354        /*
355         *  When at a "window overflow" trap, (wim == (1 << cwp)).
356         *  If we get here like that, then process a window overflow.
357         */
358
359        rd      %wim, %g4
360        srl     %g4, %l0, %g5            ! g5 = win >> cwp ; shift count and CWP
361                                         !   are LS 5 bits ; how convenient :)
362        cmp     %g5, 1                   ! Is this an invalid window?
363        bne     dont_do_the_window       ! No, then skip all this stuff
364        ! we are using the delay slot
365
366        /*
367         *  The following is same as a 1 position right rotate of WIM
368         */
369
370        srl     %g4, 1, %g5              ! g5 = WIM >> 1
371        sll     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4
372                                         ! g4 = WIM << (Number Windows - 1)
373        or      %g4, %g5, %g4            ! g4 = (WIM >> 1) |
374                                         !      (WIM << (Number Windows - 1))
375
376        /*
377         *  At this point:
378         *
379         *    g4 = the new WIM
380         *    g5 is free
381         */
382
383        /*
384         *  Since we are tinkering with the register windows, we need to
385         *  make sure that all the required information is in global registers.
386         */
387
388        save                          ! Save into the window
389        wr      %g4, 0, %wim          ! WIM = new WIM
390        nop                           ! delay slots
391        nop
392        nop
393
394        /*
395         *  Now save the window just as if we overflowed to it.
396         */
397
398        std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
399        std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
400        std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
401        std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
402
403        std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
404        std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
405        std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
406        std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
407
408        restore
409        nop
410
411dont_do_the_window:
412        /*
413         *  Global registers %g4 and %g5 are saved directly from %l4 and
414         *  %l5 directly into the ISF below.
415         */
416
417save_isf:
418
419        /*
420         *  Save the state of the interrupted task -- especially the global
421         *  registers -- in the Interrupt Stack Frame.  Note that the ISF
422         *  includes a regular minimum stack frame which will be used if
423         *  needed by register window overflow and underflow handlers.
424         *
425         *  REGISTERS SAME AS AT _ISR_Handler
426         */
427
428        sub     %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
429                                               ! make space for ISF
430
431        std     %l0, [%sp + ISF_PSR_OFFSET]    ! save psr, PC
432        st      %l2, [%sp + ISF_NPC_OFFSET]    ! save nPC
433        st      %g1, [%sp + ISF_G1_OFFSET]     ! save g1
434        std     %g2, [%sp + ISF_G2_OFFSET]     ! save g2, g3
435        std     %l4, [%sp + ISF_G4_OFFSET]     ! save g4, g5 -- see above
436        std     %g6, [%sp + ISF_G6_OFFSET]     ! save g6, g7
437
438        std     %i0, [%sp + ISF_I0_OFFSET]     ! save i0, i1
439        std     %i2, [%sp + ISF_I2_OFFSET]     ! save i2, i3
440        std     %i4, [%sp + ISF_I4_OFFSET]     ! save i4, i5
441        std     %i6, [%sp + ISF_I6_FP_OFFSET]  ! save i6/fp, i7
442
443        rd      %y, %g1
444        st      %g1, [%sp + ISF_Y_OFFSET]      ! save y
445
446        mov     %sp, %o1                       ! 2nd arg to ISR Handler
447
448        /*
449         *  Increment ISR nest level and Thread dispatch disable level.
450         *
451         *  Register usage for this section:
452         *
453         *    l4 = _Thread_Dispatch_disable_level pointer
454         *    l5 = _ISR_Nest_level pointer
455         *    l6 = _Thread_Dispatch_disable_level value
456         *    l7 = _ISR_Nest_level value
457         *
458         *  NOTE: It is assumed that l4 - l7 will be preserved until the ISR
459         *        nest and thread dispatch disable levels are unnested.
460         */
461
462        sethi    %hi(SYM(_Thread_Dispatch_disable_level)), %l4
463        ld       [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))], %l6
464        sethi    %hi(SYM(_ISR_Nest_level)), %l5
465        ld       [%l5 + %lo(SYM(_ISR_Nest_level))], %l7
466
467        add      %l6, 1, %l6
468        st       %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
469
470        add      %l7, 1, %l7
471        st       %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
472
473        /*
474         *  If ISR nest level was zero (now 1), then switch stack.
475         */
476
477        mov      %sp, %fp
478        subcc    %l7, 1, %l7             ! outermost interrupt handler?
479        bnz      dont_switch_stacks      ! No, then do not switch stacks
480
481        sethi    %hi(SYM(_CPU_Interrupt_stack_high)), %g4
482        ld       [%g4 + %lo(SYM(_CPU_Interrupt_stack_high))], %sp
483
484dont_switch_stacks:
485        /*
486         *  Make sure we have a place on the stack for the window overflow
487         *  trap handler to write into.  At this point it is safe to
488         *  enable traps again.
489         */
490
491        sub      %sp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
492
493        wr       %l0, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
494
495        /*
496         *  Vector to user's handler.
497         *
498         *  NOTE: TBR may no longer have vector number in it since
499         *        we just enabled traps.  It is definitely in l3.
500         */
501
502        sethi    %hi(SYM(_ISR_Vector_table)), %g4
503        or       %g4, %lo(SYM(_ISR_Vector_table)), %g4
504        and      %l3, 0xFF, %g5         ! remove synchronous trap indicator
505        sll      %g5, 2, %g5            ! g5 = offset into table
506        ld       [%g4 + %g5], %g4       ! g4 = _ISR_Vector_table[ vector ]
507
508
509                                        ! o1 = 2nd arg = address of the ISF
510                                        !   WAS LOADED WHEN ISF WAS SAVED!!!
511        mov      %l3, %o0               ! o0 = 1st arg = vector number
512        call     %g4, 0
513        nop                             ! delay slot
514
515        /*
516         *  Redisable traps so we can finish up the interrupt processing.
517         *  This is a VERY conservative place to do this.
518         *
519         *  NOTE: %l0 has the PSR which was in place when we took the trap.
520         */
521
522        mov      %l0, %psr             ! **** DISABLE TRAPS ****
523
524        /*
525         *  Decrement ISR nest level and Thread dispatch disable level.
526         *
527         *  Register usage for this section:
528         *
529         *    l4 = _Thread_Dispatch_disable_level pointer
530         *    l5 = _ISR_Nest_level pointer
531         *    l6 = _Thread_Dispatch_disable_level value
532         *    l7 = _ISR_Nest_level value
533         */
534
535        sub      %l6, 1, %l6
536        st       %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
537
538        st       %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
539
540        /*
541         *  If dispatching is disabled (includes nested interrupt case),
542         *  then do a "simple" exit.
543         */
544
545        orcc     %l6, %g0, %g0   ! Is dispatching disabled?
546        bnz      simple_return   ! Yes, then do a "simple" exit
547        nop                      ! delay slot
548
549        /*
550         *  If a context switch is necessary, then do fudge stack to
551         *  return to the interrupt dispatcher.
552         */
553
554        sethi    %hi(SYM(_Context_Switch_necessary)), %l4
555        ld       [%l4 + %lo(SYM(_Context_Switch_necessary))], %l5
556
557        orcc     %l5, %g0, %g0   ! Is thread switch necessary?
558        bnz      SYM(_ISR_Dispatch) ! yes, then invoke the dispatcher
559        nop                      ! delay slot
560
561        /*
562         *  Finally, check to see if signals were sent to the currently
563         *  executing task.  If so, we need to invoke the interrupt dispatcher.
564         */
565
566        sethi    %hi(SYM(_ISR_Signals_to_thread_executing)), %l6
567        ld       [%l6 + %lo(SYM(_ISR_Signals_to_thread_executing))], %l7
568
569        orcc     %l7, %g0, %g0   ! Were signals sent to the currently
570                                 !   executing thread?
571        bz       simple_return   ! yes, then invoke the dispatcher
572                                 ! use the delay slot to clear the signals
573                                 !   to the currently executing task flag
574        st       %g0, [%l6 + %lo(SYM(_ISR_Signals_to_thread_executing))]
575                                 
576
577        /*
578         *  Invoke interrupt dispatcher.
579         */
580
581        PUBLIC(_ISR_Dispatch)
582SYM(_ISR_Dispatch):
583
584        /*
585         *  The following subtract should get us back on the interrupted
586         *  tasks stack and add enough room to invoke the dispatcher.
587         *  When we enable traps, we are mostly back in the context
588         *  of the task and subsequent interrupts can operate normally.
589         */
590
591        sub      %fp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
592
593        or      %l0, SPARC_PSR_ET_MASK, %l7    ! l7 = PSR with ET=1 
594        mov     %l7, %psr                      !  **** ENABLE TRAPS ****
595        nop
596        nop
597        nop
598
599        call    SYM(_Thread_Dispatch), 0
600        nop
601
602        /*
603         *  The CWP in place at this point may be different from
604         *  that which was in effect at the beginning of the ISR if we
605         *  have been context switched between the beginning of this invocation
606         *  of _ISR_Handler and this point.  Thus the CWP and WIM should
607         *  not be changed back to their values at ISR entry time.  Any
608         *  changes to the PSR must preserve the CWP.
609         */
610
611simple_return:
612        ld      [%fp + ISF_Y_OFFSET], %l5      ! restore y
613        wr      %l5, 0, %y
614
615        ldd     [%fp + ISF_PSR_OFFSET], %l0    ! restore psr, PC
616        ld      [%fp + ISF_NPC_OFFSET], %l2    ! restore nPC
617        rd      %psr, %l3
618        and     %l3, SPARC_PSR_CWP_MASK, %l3   ! want "current" CWP
619        andn    %l0, SPARC_PSR_CWP_MASK, %l0   ! want rest from task
620        or      %l3, %l0, %l0                  ! install it later...
621        andn    %l0, SPARC_PSR_ET_MASK, %l0
622
623        /*
624         *  Restore tasks global and out registers
625         */
626
627        mov    %fp, %g1
628
629                                              ! g1 is restored later
630        ldd     [%fp + ISF_G2_OFFSET], %g2    ! restore g2, g3
631        ldd     [%fp + ISF_G4_OFFSET], %g4    ! restore g4, g5
632        ldd     [%fp + ISF_G6_OFFSET], %g6    ! restore g6, g7
633
634        ldd     [%fp + ISF_I0_OFFSET], %i0    ! restore i0, i1
635        ldd     [%fp + ISF_I2_OFFSET], %i2    ! restore i2, i3
636        ldd     [%fp + ISF_I4_OFFSET], %i4    ! restore i4, i5
637        ldd     [%fp + ISF_I6_FP_OFFSET], %i6 ! restore i6/fp, i7
638
639        /*
640         *  Registers:
641         *
642         *   ALL global registers EXCEPT G1 and the input registers have
643         *   already been restored and thuse off limits.
644         *
645         *   The following is the contents of the local registers:
646         *
647         *     l0 = original psr
648         *     l1 = return address (i.e. PC)
649         *     l2 = nPC
650         *     l3 = CWP
651         */
652
653        /*
654         *  if (CWP + 1) is an invalid window then we need to reload it.
655         *
656         *  WARNING: Traps should now be disabled
657         */
658
659        mov     %l0, %psr                  !  **** DISABLE TRAPS ****
660        nop
661        nop
662        nop
663        rd      %wim, %l4
664        add     %l0, 1, %l6                ! l6 = cwp + 1
665        and     %l6, SPARC_PSR_CWP_MASK, %l6 ! do the modulo on it
666        srl     %l4, %l6, %l5              ! l5 = win >> cwp + 1 ; shift count
667                                           !  and CWP are conveniently LS 5 bits
668        cmp     %l5, 1                     ! Is tasks window invalid?
669        bne     good_task_window
670
671        /*
672         *  The following code is the same as a 1 position left rotate of WIM.
673         */
674
675        sll     %l4, 1, %l5                ! l5 = WIM << 1
676        srl     %l4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
677                                           ! l4 = WIM >> (Number Windows - 1)
678        or      %l4, %l5, %l4              ! l4 = (WIM << 1) |
679                                           !      (WIM >> (Number Windows - 1))
680
681        /*
682         *  Now restore the window just as if we underflowed to it.
683         */
684
685        wr      %l4, 0, %wim               ! WIM = new WIM
686        nop                                ! must delay after writing WIM
687        nop
688        nop
689        restore                            ! now into the tasks window
690
691        ldd     [%g1 + CPU_STACK_FRAME_L0_OFFSET], %l0
692        ldd     [%g1 + CPU_STACK_FRAME_L2_OFFSET], %l2
693        ldd     [%g1 + CPU_STACK_FRAME_L4_OFFSET], %l4
694        ldd     [%g1 + CPU_STACK_FRAME_L6_OFFSET], %l6
695        ldd     [%g1 + CPU_STACK_FRAME_I0_OFFSET], %i0
696        ldd     [%g1 + CPU_STACK_FRAME_I2_OFFSET], %i2
697        ldd     [%g1 + CPU_STACK_FRAME_I4_OFFSET], %i4
698        ldd     [%g1 + CPU_STACK_FRAME_I6_FP_OFFSET], %i6
699                                           ! reload of sp clobbers ISF
700        save                               ! Back to ISR dispatch window
701
702good_task_window:
703
704        mov     %l0, %psr                  !  **** DISABLE TRAPS ****
705                                           !  and restore condition codes.
706        ld      [%g1 + ISF_G1_OFFSET], %g1 ! restore g1
707        jmp     %l1                        ! transfer control and
708        rett    %l2                        ! go back to tasks window
709
710/* end of file */
Note: See TracBrowser for help on using the repository browser.