summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/sparc/reg_win/window.S
blob: c21e73ebb484c8f127a03387dd1a9b09c04220e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
 *  window.s
 *
 *  This file contains the register window management routines for the 
 *  SPARC architecture.  Trap handlers for the following capabilities
 *  are included in this file:
 *
 *    + Window Overflow
 *    + Window Underflow
 *    + Flushing All Windows
 * 
 *  COPYRIGHT:
 *
 *  This file includes the window overflow and underflow handlers from 
 *  the file srt0.s provided with the binary distribution of the SPARC 
 *  Instruction Simulator (SIS) found at 
 *  ftp://ftp.estec.esa.nl/pub/ws/wsd/erc32.
 *
 *  COPYRIGHT (c) 1995. European Space Agency.
 *
 *  This terms of the RTEMS license apply to this file.
 *
 *  $Id$
 */

#include <asm.h>

        .seg    "text"
        /*
         *  Window overflow trap handler.
         *
         *  On entry:
         *
         *    l0 = psr (from trap table)
         *    l1 = pc
         *    l2 = npc
         */

        PUBLIC(window_overflow_trap_handler)

SYM(window_overflow_trap_handler):

        /*
         *  Calculate new WIM by "rotating" the valid bits in the WIM right 
         *  by one position.  The following shows how the bits move for a SPARC
         *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
         *
         *    OLD WIM = 76543210
         *    NEW WIM = 07654321
         *
         *  NOTE: New WIM must be stored in a global register since the
         *        "save" instruction just prior to the load of the wim 
         *        register will result in the local register set changing.
         */

        mov  %wim, %l3                   ! l3 = WIM
        mov  %g1, %l7                    ! save g1
        srl  %l3, 1, %g1                 ! g1 = WIM >> 1
        sll  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
                                         ! l4 = WIM << (Number Windows - 1)
        or   %l4, %g1, %g1               ! g1 = (WIM >> 1) | 
                                         !      (WIM << (Number Windows - 1))

        save                             ! Get into window to be saved.
        mov  %g1, %wim                   ! load new WIM
        nop; nop; nop                    ! 3 slot delay
        std  %l0, [%sp + 0x00]           ! save local register set
        std  %l2, [%sp + 0x08]
        std  %l4, [%sp + 0x10]
        std  %l6, [%sp + 0x18]
        std  %i0, [%sp + 0x20]           ! save input register set
        std  %i2, [%sp + 0x28]
        std  %i4, [%sp + 0x30]
        std  %i6, [%sp + 0x38]
        restore                          ! Go back to trap window.
        mov  %l7, %g1                    ! restore g1
        jmp  %l1                         ! Re-execute save.
        rett %l2

        /*
         *  Window underflow trap handler.
         *
         *  On entry:
         *
         *    l0 = psr (from trap table)
         *    l1 = pc
         *    l2 = npc
         */

        PUBLIC(window_underflow_trap_handler)

SYM(window_underflow_trap_handler):

        /*
         *  Calculate new WIM by "rotating" the valid bits in the WIM left 
         *  by one position.  The following shows how the bits move for a SPARC
         *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
         *
         *    OLD WIM = 76543210
         *    NEW WIM = 07654321
         *
         *  NOTE: New WIM must be stored in a global register since the
         *        "save" instruction just prior to the load of the wim 
         *        register will result in the local register set changing.
         */

        mov  %wim, %l3                  ! Calculate new WIM
        sll  %l3, 1, %l4                ! l4 = WIM << 1
        srl  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1, %l5
                                        ! l5 = WIM >> (Number Windows-1)
        or   %l5, %l4, %l5              ! l5 = (WIM << 1) |
                                        !      (WIM >> (Number Windows-1))
        mov  %l5, %wim                  ! load the new WIM
        nop; nop; nop
        restore                         ! Two restores to get into the
        restore                         ! window to restore
        ldd  [%sp + 0x00], %l0          ! First the local register set
        ldd  [%sp + 0x08], %l2
        ldd  [%sp + 0x10], %l4
        ldd  [%sp + 0x18], %l6
        ldd  [%sp + 0x20], %i0          ! Then the input registers
        ldd  [%sp + 0x28], %i2
        ldd  [%sp + 0x30], %i4
        ldd  [%sp + 0x38], %i6
        save                            ! Get back to the trap window.
        save
        jmp  %l1                        ! Re-execute restore.
        rett  %l2

        /*
         *  Flush All Windows trap handler.
         *
         *  Flush all windows with valid contents except the current one
         *  and the one we will be returning to.
         *
         *  In examining the set register windows, one may logically divide
         *  the windows into sets (some of which may be empty) based on their
         *  current status:
         *
         *    + current (i.e. in use),
         *    + used (i.e. a restore would not trap)
         *    + invalid (i.e. 1 in corresponding bit in WIM)
         *    + unused
         *
         *  Either the used or unused set of windows may be empty.
         *
         *  NOTE: We assume only one bit is set in the WIM at a time.
         *
         *  Given a CWP of 5 and a WIM of 0x1, the registers are divided
         *  into sets as follows:
         *
         *    + 0   - invalid
         *    + 1-4 - unused
         *    + 5   - current
         *    + 6-7 - used
         *
         *  In this case, we only would save the used windows which we
         *  will not be returning to -- 6.
         *
         *    Register Usage while saving the windows:
         *      g1 = current PSR
         *      g2 = current wim
         *      g3 = CWP
         *      g4 = wim scratch
         *      g5 = scratch
         *
         *  On entry:
         *
         *    l0 = psr (from trap table)
         *    l1 = pc
         *    l2 = npc
         */
 
        PUBLIC(window_flush_trap_handler)
 
SYM(window_flush_trap_handler):
        /*
         *  Save the global registers we will be using
         */

        mov     %g1, %l3
        mov     %g2, %l4
        mov     %g3, %l5
        mov     %g4, %l6
        mov     %g5, %l7

        mov     %l0, %g1                      ! g1 = psr
        mov     %wim, %g2                     ! g2 = wim
        and     %l0, SPARC_PSR_CWP_MASK, %g3  ! g3 = CWP

        add     %g3, 1, %g5                   ! g5 = CWP + 1
        and     %g5, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g5

        mov     1, %g4
        sll     %g4, %g5, %g4                 ! g4 = WIM mask for CWP+1 invalid

        restore                               ! go back one register window
 
save_frame_loop:
        sll     %g4, 1, %g5                   ! rotate the "wim" left 1
        srl     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
        or      %g4, %g5, %g4                 ! g4 = wim if we do one restore
 
        /*
         *  If a restore would not underflow, then continue.
         */
 
        andcc   %g4, %g2, %g0                 ! Any windows to flush?
        bnz     done_flushing                 ! No, then continue
        nop
 
        restore                               ! back one window
 
        /*
         *  Now save the window just as if we overflowed to it.
         */
 
        std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
        std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
        std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
        std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
 
        std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
        std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
        std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
        std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
 
        ba      save_frame_loop
        nop
 
done_flushing:
 
        add     %g3, 2, %g3                   ! calculate desired WIM
        and     %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
        mov     1, %g4
        sll     %g4, %g3, %g4                 ! g4 = new WIM
        mov     %g4, %wim
 
        mov     %g1, %psr                     ! restore PSR
        nop
        nop
        nop

        /*
         *  Restore the global registers we used
         */

        mov     %l3, %g1
        mov     %l4, %g2
        mov     %l5, %g3
        mov     %l6, %g4
        mov     %l7, %g5

        jmpl    %l2, %g0
        rett    %l2 + 4

/* end of file */