source: rtems/c/src/exec/score/cpu/sparc/cpu_asm.S @ 4159370

4.104.114.84.95
Last change on this file since 4159370 was 4159370, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 11, 2000 at 9:16:53 PM

Reworked score/cpu/sparc so it can be safely compiled multilib. All
routines and structures that require CPU model specific information
are now in libcpu. This primarily required moving erc32 specific
information from score/cpu files to libcpu/sparc and the erc32 BSP.

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