source: rtems/cpukit/score/cpu/m68k/cpu_asm.S @ da42259

4.104.115
Last change on this file since da42259 was 3b7e9bc, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 05/15/09 at 07:20:38

cpu.c, cpu_asm.S, rtems/score/cpu.h: Cleanup of the floating point context initialization, save and restore code.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*  cpu_asm.s
2 *
3 *  This file contains all assembly code for the MC68020 implementation
4 *  of RTEMS.
5 *
6 *  COPYRIGHT (c) 1989-2008.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.com/license/LICENSE.
12 *
13 *  $Id$
14 */
15
16
17#include <rtems/asm.h>
18
19/*  void _CPU_Context_switch( run_context, heir_context )
20 *
21 *  This routine performs a normal non-FP context.
22 */
23
24        .align  4
25        .global SYM (_CPU_Context_switch)
26
27.set RUNCONTEXT_ARG,   4                 | save context argument
28.set HEIRCONTEXT_ARG,  8                 | restore context argument
29
30SYM (_CPU_Context_switch):
31          moval    a7@(RUNCONTEXT_ARG),a0| a0 = running thread context
32          movw     sr,d1                 | d1 = status register
33          movml    d1-d7/a2-a7,a0@       | save context
34
35          moval    a7@(HEIRCONTEXT_ARG),a0| a0 = heir thread context
36
37#if defined( __mcoldfire__ ) && ( M68K_HAS_FPU == 1 )
38          moveb    a0@(13*4),d0                 | get context specific DF bit info in d0
39          btstb    #4,d0                        | test context specific DF bit info
40          beq      fpu_on                       | branch if FPU needs to be switched on
41
42fpu_off:  movl     _CPU_cacr_shadow,d0          | get content of _CPU_cacr_shadow in d0
43          btstl    #4,d0                        | test DF bit info in d0
44          bne      restore                      | branch if FPU is already switched off
45          bsetl    #4,d0                        | set DF bit in d0
46          bra      cacr_set                     | branch to set the new FPU setting in cacr and _CPU_cacr_shadow
47
48fpu_on:   movl     _CPU_cacr_shadow,d0          | get content of _CPU_cacr_shadow in d1
49          btstl    #4,d0                        | test context specific DF bit info
50          beq      restore                      | branch if FPU is already switched on
51          bclrl    #4,d0                        | clear DF bit info in d0
52
53cacr_set: movew    sr,d1                        | get content of sr in d1
54          oril     #0x00000700,d1               | mask d1
55          movew    d1,sr                        | disable all interrupts
56          movl     d0,_CPU_cacr_shadow          | move _CPU_cacr_shadow to d1
57          movec    d0,cacr                      | enable FPU in cacr
58#endif
59
60restore:  movml    a0@,d1-d7/a2-a7       | restore context
61          movw     d1,sr                 | restore status register
62          rts
63
64/*
65 * Floating point context save and restore.
66 *
67 * The code for the MC68881 or MC68882 is based upon the code shown on pages
68 * 6-38 of the MC68881/68882 Users Manual (rev 1).  CPU_FP_CONTEXT_SIZE is
69 * higher than expected to account for the -1 pushed at end of this sequence.
70 */
71
72#if ( CPU_HARDWARE_FP == TRUE )
73
74.set FPCONTEXT_ARG,   4                   | save FP context argument
75
76        .align  4
77        .global SYM (_CPU_Context_save_fp)
78SYM (_CPU_Context_save_fp):
79
80        /* Get context save area pointer argument from the stack */
81        moval    a7@(FPCONTEXT_ARG), a1
82        moval    a1@, a0
83
84  #if defined( __mcoldfire__ )
85        /* Move MACSR to data register and disable rounding */
86        movel    macsr, d0
87        clrl     d1
88        movl     d1, macsr
89
90        /* Save MACSR and ACC0 */
91        movl     acc0, d1
92        moveml   d0-d1, a0@(0)
93
94        /* Save ACC1 and ACC2 */
95        movl     acc1, d0
96        movl     acc2, d1
97        moveml   d0-d1, a0@(8)
98
99        /* Save ACC3 and ACCEXT01 */
100        movl     acc3, d0
101        movl     accext01, d1
102        moveml   d0-d1, a0@(16)
103
104        /* Save ACCEXT23 and MASK */
105        movl     accext23, d0
106        movl     mask, d1
107        moveml   d0-d1, a0@(24)
108
109    #if ( M68K_HAS_FPU == 1 )
110        /* Save FP state */
111        fsave    a0@(32)
112
113        /* Save FP instruction address */
114        fmovel   fpi, a0@(48)
115
116        /* Save FP data */
117        fmovem   fp0-fp7, a0@(52)
118    #endif
119  #else
120    #if defined( __mc68060__ )
121        lea      a0@(-M68K_FP_STATE_SIZE), a0
122        fsave    a0@                      | save 68060 state frame
123    #else
124        fsave    a0@-                     | save 68881/68882 state frame
125    #endif
126        tstb     a0@                      | check for a null frame
127        beq.b    nosv                     | Yes, skip save of user model
128        fmovem   fp0-fp7, a0@-            | save data registers (fp0-fp7)
129        fmovem   fpc/fps/fpi, a0@-        | and save control registers
130        movl     #-1, a0@-                | place not-null flag on stack
131nosv:
132        movl     a0, a1@                  | save pointer to saved context
133  #endif
134
135        /* Return */
136        rts
137
138        .align  4
139        .global SYM (_CPU_Context_restore_fp)
140SYM (_CPU_Context_restore_fp):
141
142        /* Get context save area pointer argument from the stack */
143        moval    a7@(FPCONTEXT_ARG), a1
144        moval    a1@, a0
145
146  #if defined( __mcoldfire__ )
147    #if ( M68K_HAS_FPU == 1 )
148        /* Restore FP data */
149        fmovem   a0@(52), fp0-fp7
150
151        /* Restore FP instruction address */
152        fmovel   a0@(48), fpi
153
154        /* Restore FP state */
155        frestore a0@(32)
156    #endif
157
158        /* Disable rounding */
159        clrl     d0
160        movl     d0, macsr
161
162        /* Restore MASK and ACCEXT23 */
163        moveml   a0@(24), d0-d1
164        movl     d0, mask
165        movl     d1, accext23
166
167        /* Restore ACCEXT01 and ACC3 */
168        moveml   a0@(16), d0-d1
169        movl     d0, accext01
170        movl     d1, acc3
171
172        /* Restore ACC2 and ACC1 */
173        moveml   a0@(8), d0-d1
174        movl     d0, acc2
175        movl     d1, acc1
176
177        /* Restore ACC0 and MACSR */
178        moveml   a0@(0), d0-d1
179        movl     d0, acc0
180        movl     d1, macsr
181  #else
182        tstb     a0@                      | Null context frame?
183        beq.b    norst                    | Yes, skip fp restore
184        addql    #4, a0                   | throwaway non-null flag
185        fmovem   a0@+, fpc/fps/fpi        | restore control registers
186        fmovem   a0@+, fp0-fp7            | restore data regs (fp0-fp7)
187norst:
188    #if defined( __mc68060__ )
189        frestore a0@                      | restore 68060 state frame
190        lea      a0@(M68K_FP_STATE_SIZE), a0
191    #else
192        frestore a0@+                     | restore 68881/68882 state frame
193    #endif
194        movl     a0, a1@                  | save pointer to saved context
195  #endif
196
197        /* Return */
198        rts
199#endif
200
201/*PAGE
202 *  void _ISR_Handler()
203 *
204 *  This routine provides the RTEMS interrupt management.
205 *
206 *  NOTE:
207 *    Upon entry, the master stack will contain an interrupt stack frame
208 *    back to the interrupted thread and the interrupt stack will contain
209 *    a throwaway interrupt stack frame.  If dispatching is enabled, and this
210 *    is the outer most interrupt, and a context switch is necessary or
211 *    the current thread has pending signals, then set up the master stack to
212 *    transfer control to the interrupt dispatcher.
213 */
214
215#if ( defined(__mcoldfire__) )
216.set SR_OFFSET,    2                     | Status register offset
217.set PC_OFFSET,    4                     | Program Counter offset
218.set FVO_OFFSET,   0                     | Format/vector offset
219#elif ( M68K_HAS_VBR == 1)
220.set SR_OFFSET,    0                     | Status register offset
221.set PC_OFFSET,    2                     | Program Counter offset
222.set FVO_OFFSET,   6                     | Format/vector offset
223#else
224.set SR_OFFSET,    2                     | Status register offset
225.set PC_OFFSET,    4                     | Program Counter offset
226.set FVO_OFFSET,   0                     | Format/vector offset placed in the stack
227#endif /* M68K_HAS_VBR */
228
229.set SAVED,        16                    | space for saved registers
230
231        .align  4
232        .global SYM (_ISR_Handler)
233
234SYM (_ISR_Handler):
235                                         | disable multitasking
236        addql   #1,SYM (_Thread_Dispatch_disable_level)
237#if ( !defined(__mcoldfire__) )
238        moveml  d0-d1/a0-a1,a7@-         | save d0-d1,a0-a1
239#else
240        lea     a7@(-SAVED),a7
241        movm.l  d0-d1/a0-a1,a7@          | save d0-d1,a0-a1
242#endif
243        movew   a7@(SAVED+FVO_OFFSET),d0 | d0 = F/VO
244        andl    #0x03fc,d0               | d0 = vector offset in vbr
245
246
247#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 )
248        | Make a0 point just above interrupt stack
249        movel   _CPU_Interrupt_stack_high,a0
250        cmpl    _CPU_Interrupt_stack_low,a7  | stack below interrupt stack?
251        bcs.b   1f                      | yes, switch to interrupt stack
252        cmpl    a0,a7                   | stack above interrupt stack?
253        bcs.b   2f                      | no, do not switch stacks
2541:
255        movel   a7,a1                   | copy task stack pointer
256        movel   a0,a7                   | switch to interrupt stack
257        movel   a1,a7@-                 | store task stack pointer
258                                        |     on interrupt stack
2592:
260#endif /* CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 */
261
262        addql   #1,SYM(_ISR_Nest_level) | one nest level deeper
263
264        movel   SYM (_ISR_Vector_table),a0 | a0= base of RTEMS table
265#if ( M68K_HAS_PREINDEXING == 1 )
266        movel   (a0,d0:w:1),a0           | a0 = address of user routine
267#else
268        addal   d0,a0                    | a0 = address of vector
269        movel   (a0),a0                  | a0 = address of user routine
270#endif
271
272        lsrl    #2,d0                    | d0 = vector number
273        movel   d0,a7@-                  | push vector number
274        jbsr    a0@                      | invoke the user ISR
275        addql   #4,a7                    | remove vector number
276        subql   #1,SYM(_ISR_Nest_level)  | Reduce interrupt-nesting count
277
278#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 )
279        movel   _CPU_Interrupt_stack_high,a0
280        subql   #4,a0
281        cmpl    a0,a7                   | At top of interrupt stack?
282        bne.b   1f                      | No, do not restore task stack pointer
283        movel   (a7),a7                 | Restore task stack pointer
2841:
285#endif /* CPU_HAS_SOFTWARE_INTERRUPT_STACK == 1 */
286        subql   #1,SYM (_Thread_Dispatch_disable_level)
287                                         | unnest multitasking
288        bne.b    exit                    | If dispatch disabled, exit
289
290#if ( M68K_HAS_SEPARATE_STACKS == 1 )
291        movew   #0xf000,d0               | isolate format nibble
292        andw    a7@(SAVED+FVO_OFFSET),d0 | get F/VO
293        cmpiw   #0x1000,d0               | is it a throwaway isf?
294        bne.b   exit                     | NOT outer level, so branch
295#else
296/*
297 * If we have a CPU which allows a higher-priority interrupt to preempt a
298 * lower priority handler before the lower-priority handler can increment
299 * _Thread_Dispatch_disable_level then we must check the PC on the stack to
300 * see if it is _ISR_Handler.  If it is we have the case of nesting interrupts
301 * without the dispatch level being incremented.
302 */
303  #if ( !defined(__mcoldfire__) && !__mc68060__ )
304        cmpl    #_ISR_Handler,a7@(SAVED+PC_OFFSET)
305        beq.b   exit
306  #endif
307#endif
308        tstb    SYM (_Context_Switch_necessary)
309                                         | Is thread switch necessary?
310        bne.b   bframe                   | Yes, invoke dispatcher
311
312        tstb    SYM (_ISR_Signals_to_thread_executing)
313                                         | signals sent to Run_thread
314                                         |   while in interrupt handler?
315        beq.b   exit                     | No, then exit
316
317bframe: clrb    SYM (_ISR_Signals_to_thread_executing)
318                                         | If sent, will be processed
319#if ( M68K_HAS_SEPARATE_STACKS == 1 )
320        movec   msp,a0                   | a0 = master stack pointer
321        movew   #0,a0@-                  | push format word
322        movel   #SYM(_ISR_Dispatch),a0@- | push return addr
323        movew   a0@(6),a0@-              | push saved sr
324        movec   a0,msp                   | set master stack pointer
325#else
326        jsr SYM (_Thread_Dispatch)       | Perform context switch
327#endif
328
329#if ( !defined(__mcoldfire__) )
330exit:   moveml  a7@+,d0-d1/a0-a1         | restore d0-d1,a0-a1
331#else
332exit:   moveml  a7@,d0-d1/a0-a1          | restore d0-d1,a0-a1
333        lea     a7@(SAVED),a7
334#endif
335
336#if ( M68K_HAS_VBR == 0 )
337        addql   #2,a7                    | pop format/id
338#endif /* M68K_HAS_VBR */
339        rte                              | return to thread
340                                         |   OR _Isr_dispatch
341
342/*PAGE
343 *  void _ISR_Dispatch()
344 *
345 *  Entry point from the outermost interrupt service routine exit.
346 *  The current stack is the supervisor mode stack if this processor
347 *  has separate stacks.
348 *
349 *    1.  save all registers not preserved across C calls.
350 *    2.  invoke the _Thread_Dispatch routine to switch tasks
351 *        or a signal to the currently executing task.
352 *    3.  restore all registers not preserved across C calls.
353 *    4.  return from interrupt
354 */
355
356        .global SYM (_ISR_Dispatch)
357SYM (_ISR_Dispatch):
358#if ( !defined(__mcoldfire__) )
359        movml   d0-d1/a0-a1,a7@-
360        jsr     SYM (_Thread_Dispatch)
361        movml   a7@+,d0-d1/a0-a1
362#else
363        lea     a7@(-SAVED),a7
364        movml   d0-d1/a0-a1,a7@
365        jsr     SYM (_Thread_Dispatch)
366        movml   a7@,d0-d1/a0-a1
367        lea     a7@(SAVED),a7
368#endif
369
370#if ( M68K_HAS_VBR == 0 )
371        addql   #2,a7                    | pop format/id
372#endif /* M68K_HAS_VBR */
373        rte
Note: See TracBrowser for help on using the repository browser.