OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [m68k/] [arch/] [current/] [src/] [hal_arch.S] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
// #========================================================================
2
// #
3
// #    hal_arch.S
4
// #
5
// #    M68K support for contexts, exceptions and interrupts
6
// #
7
// #========================================================================
8
//=============================================================================
9
// ####ECOSGPLCOPYRIGHTBEGIN####
10
// -------------------------------------------
11
// This file is part of eCos, the Embedded Configurable Operating System.
12
// Copyright (C) 2003, 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
13
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later
17
// version.
18
//
19
// eCos is distributed in the hope that it will be useful, but WITHOUT
20
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22
// for more details.
23
//
24
// You should have received a copy of the GNU General Public License
25
// along with eCos; if not, write to the Free Software Foundation, Inc.,
26
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
27
//
28
// As a special exception, if other files instantiate templates or use
29
// macros or inline functions from this file, or you compile this file
30
// and link it with other works to produce a work based on this file,
31
// this file does not by itself cause the resulting work to be covered by
32
// the GNU General Public License. However the source code for this file
33
// must still be made available in accordance with section (3) of the GNU
34
// General Public License v2.
35
//
36
// This exception does not invalidate any other reasons why a work based
37
// on this file might be covered by the GNU General Public License.
38
// -------------------------------------------
39
// ####ECOSGPLCOPYRIGHTEND####
40
//============================================================================
41
//###DESCRIPTIONBEGIN####
42
//
43
// Author(s):     bartv
44
// Date:          2003-06-04
45
//
46
//###DESCRIPTIONEND####
47
//========================================================================
48
 
49
        .file   "hal_arch.S"
50
 
51
#include 
52
#include 
53
#include 
54
#ifdef CYGPKG_KERNEL
55
        // For instrumentation options
56
# include 
57
#endif
58
#include 
59
 
60
// ----------------------------------------------------------------------------
61
// The system startup and/or interrupt stack, unless the platform HAL
62
// provides its own.
63
//
64
// The default behaviour is a separate interrupt stack via common HAL
65
// configuration options, with the interrupt stack reused as the
66
// startup stack. If the use of an interrupt stack is disabled then
67
// a separate startup stack is needed. Either the startup stack, the
68
// interrupt stack, or both can be provided by the platform HAL, for
69
// example to place the stack in an area of memory that is not otherwise
70
// readily usable.
71
 
72
#if defined(_HAL_M68K_INSTANTIATE_STARTUP_STACK_) || defined(_HAL_M68K_INSTANTIATE_INTERRUPT_STACK_)
73
        .section        .bss
74
        .balign         4
75
# ifdef _HAL_M68K_INSTANTIATE_STARTUP_STACK_
76
        .global         _hal_m68k_startup_stack_base_
77
_hal_m68k_startup_stack_base_:
78
# endif
79
# ifdef _HAL_M68K_INSTANTIATE_INTERRUPT_STACK_
80
        .global         _hal_m68k_interrupt_stack_base_
81
_hal_m68k_interrupt_stack_base_:
82
# endif
83
# ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
84
        .rept   CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
85
        .byte   0
86
        .endr
87
        .balign 4
88
# else
89
        .rept   CYGNUM_HAL_M68K_STARTUP_STACK_SIZE
90
        .byte   0
91
        .endr
92
        .balign 4
93
# endif
94
# ifdef _HAL_M68K_INSTANTIATE_STARTUP_STACK_
95
        .global _hal_m68k_startup_stack_
96
_hal_m68k_startup_stack_:
97
# endif
98
# ifdef _HAL_M68K_INSTANTIATE_INTERRUPT_STACK_
99
        .global _hal_m68k_interrupt_stack_
100
_hal_m68k_interrupt_stack_:
101
# endif
102
 
103
#endif
104
 
105
// ----------------------------------------------------------------------------
106
// M68K calling conventions.
107
//
108
// The stack pointer always points at the first word of the stack that
109
// is currently in use. Pushing additional data requires a predecrement.
110
//
111
// Frame pointers are not required but the compiler usually defaults to
112
// using them, to make debugging easier. This assembler code typically
113
// does not use a frame pointer.
114
//
115
// All arguments are pushed onto the stack, never in registers. D0 is
116
// used for return values.
117
//
118
// According to CALL_USED_REGISTERS in gcc/config/m68k/m68k.h,
119
// d0/d1/a0/a1/fp0/fp1 are caller-save, i.e. must be saved in an interrupt
120
// handler but can be ignored in a function called from C. The fp status
121
// registers are also caller-save.
122
//
123
// d2-d7/a2-a6/fp2-fp7 are callee-save registers, i.e. must be saved by
124
// a C function. fpsr is not callee-save, a C function can perform floating
125
// point operations and hence clobber the status. Similarly fpiar is not
126
// callee-save. fpcr is
127
//
128
// Floating point support is only available on some variants. There can also
129
// be other hardware units such as multiply-accumulators which may have state
130
// that should be saved.
131
 
132
// ----------------------------------------------------------------------------
133
// Context switch support.
134
//
135
// The context consists of generic integer registers, possibly floating
136
// point registers, possibly another hardware unit, and space for pc/sr
137
// at the end in a variant-specific format.
138
 
139
        .equ    hal_context_integer_offset,     0
140
        .equ    hal_context_integer_d0_offset,  0
141
        .equ    hal_context_integer_d2_offset,  (2 * 4)
142
        .equ    hal_context_integer_a0_offset,  (8 * 4)
143
        .equ    hal_context_integer_a2_offset,  ((8+2) * 4)
144
        .equ    hal_context_integer_size,       (15 * 4)
145
 
146
        .equ    hal_context_fpu_offset,         (hal_context_integer_offset + hal_context_integer_size)
147
#ifdef CYGIMP_HAL_M68K_FPU_SAVE
148
        .equ    hal_context_fpu_fpsr_offset,    (hal_context_fpu_offset + 0)
149
        .equ    hal_context_fpu_fpiar_offset,   (hal_context_fpu_offset + 4)
150
        .equ    hal_context_fpu_fp0_offset,     (hal_context_fpu_offset + 8)
151
        .equ    hal_context_fpu_fp2_offset,     (hal_context_fpu_fp0_offset + (2 * 12))
152
        .equ    hal_context_fpu_size,           ((2 * 4) + (8 * 12))
153
#else
154
        .equ    hal_context_fpu_size,           0
155
#endif
156
 
157
        .equ    hal_context_other_offset,       (hal_context_fpu_offset + hal_context_fpu_size)
158
#ifdef HAL_CONTEXT_OTHER_SIZE
159
        .equ    hal_context_other_size,         HAL_CONTEXT_OTHER_SIZE
160
#else
161
        .equ    hal_context_other_size,         0
162
#endif
163
 
164
        .equ    hal_context_pcsr_offset,        (hal_context_other_offset + hal_context_other_size)
165
#ifdef HAL_CONTEXT_PCSR_SIZE
166
        .equ    hal_context_pcsr_size,          HAL_CONTEXT_PCSR_SIZE
167
#else
168
        .equ    hal_context_pcsr_size,          8
169
#endif
170
        .equ    hal_context_size,               (hal_context_pcsr_offset + hal_context_pcsr_size)
171
 
172
// The offset to be used when switching to a new thread. For some variants
173
// this is 0 because the rte instruction will pop the entire pcsr part of
174
// the structure. For other variants some additional data may have to be popped.
175
#ifdef HAL_CONTEXT_PCSR_RTE_ADJUST
176
        .equ    hal_context_rte_adjust,         (hal_context_pcsr_offset + HAL_CONTEXT_PCSR_RTE_ADJUST)
177
#else
178
        .equ    hal_context_rte_adjust,         hal_context_pcsr_offset
179
#endif
180
 
181
 
182
// Definitions for saving/restoring FPU context, if the FPU is part of the
183
// saved context. It can be assumed that %sp points at the thread context.
184
// FIXME: this code should probably use fsave/frestore to ensure that
185
// floating point operations have completed.
186
#ifdef CYGIMP_HAL_M68K_FPU_SAVE
187
 
188
        .macro  hal_context_fpu_save_caller areg=%sp
189
        fmove.l         %fpsr, hal_context_fpu_fpsr_offset(\areg)
190
        fmove.l         %fpiar, hal_context_fpu_fpiar_offset(\areg)
191
        fmovem.x        %fp0-%fp1, hal_context_fpu_fp0_offset(\areg)
192
        .endm
193
 
194
        .macro  hal_context_fpu_load_caller areg=%sp
195
        fmove.l         hal_context_fpu_fpsr_offset(\areg), %fpisr
196
        fmove.l         hal_context_fpu_fpiar_offset(\areg), %fpiar
197
        fmovem.x        hal_context_fpu_fp0_offset(\areg),%fp0-%fp1
198
        .endm
199
 
200
        .macro  hal_context_fpu_save_callee areg=%sp
201
        fmovem.x        %fp2-%fp7, hal_context_fpu_fp2_offset(\areg)
202
        .endm
203
 
204
        .macro  hal_context_fpu_load_callee areg=%sp
205
        fmovem.x        hal_context_fpu_fp2_offset(\areg), %fp2-%fp7
206
        .endm
207
 
208
        .macro  hal_context_fpu_save_all areg=%sp
209
        fmove.l         %fpsr, hal_context_fpu_fpsr_offset(\areg)
210
        fmove.l         %fpiar, hal_context_fpu_fpiar_offset(\areg)
211
        fmovem.x        %fp0-%fp7, hal_context_fpu_fp0_offset(\areg)
212
        .endm
213
 
214
        .macro  hal_context_fpu_load_all areg=%sp
215
        fmove.l         hal_context_fpu_fpsr_offset(\areg), %fpsr
216
        fmove.l         hal_context_fpu_fpiar_offset(\areg), %fpiar
217
        fmovem.x        hal_context_fpu_fp0_offset(\areg), %fp0-%fp7
218
        .endm
219
#else
220
        .macro hal_context_fpu_save_caller areg=%sp
221
        .endm
222
        .macro hal_context_fpu_load_caller areg=%sp
223
        .endm
224
        .macro hal_context_fpu_save_callee areg=%sp
225
        .endm
226
        .macro hal_context_fpu_load_callee areg=%sp
227
        .endm
228
        .macro hal_context_fpu_save_all areg=%sp
229
        .endm
230
        .macro hal_context_fpu_load_all areg=%sp
231
        .endm
232
#endif
233
 
234
// No-op defaults for saving/restoring the OTHER context. If there is in fact
235
// something to be done then the variant HAL should have defined
236
// HAL_CONTEXT_OTHER_SIZE
237
#ifndef HAL_CONTEXT_OTHER_SIZE
238
        .macro hal_context_other_save_caller areg=%sp
239
        .endm
240
        .macro hal_context_other_load_caller areg=%sp
241
        .endm
242
        .macro hal_context_other_save_callee areg=%sp
243
        .endm
244
        .macro hal_context_other_load_callee areg=%sp
245
        .endm
246
        .macro hal_context_other_save_all areg=%sp
247
        .endm
248
        .macro hal_context_other_load_all areg=%sp
249
        .endm
250
#endif
251
 
252
// ----------------------------------------------------------------------------
253
// LOAD_CONTEXT is called to start a new thread, usually only during system
254
// startup.
255
//
256
// void hal_thread_load_context(void* sp)
257
 
258
        FUNC_START(hal_thread_load_context)
259
        move.l  4(%sp),%sp
260
        hal_context_other_load_all
261
        hal_context_fpu_load_all
262
        movem.l hal_context_integer_offset(%sp),%d0-%d7/%a0-%a6
263
        add.l   #hal_context_rte_adjust, %sp
264
        rte
265
 
266
// ----------------------------------------------------------------------------
267
// void hal_thread_switch_context(void** from, void* to)
268
 
269
        FUNC_START(hal_thread_switch_context)
270
 
271
        // Space for the saved thread context. The PC is already on the
272
        // stack.  "from" is on the stack immediately after the context,
273
        // then "to".
274
        mov.l   4(%sp),%a0
275
        sub.l   # (hal_context_size - 4), %sp
276
        mov.l   %sp, 0(%a0)
277
 
278
#ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
279
        // Save all the callee-save integer registers, so that they become
280
        // available to the other macros.
281
        movem.l %d2-%d7, hal_context_integer_d2_offset(%sp)
282
        movem.l %a2-%a6, hal_context_integer_a2_offset(%sp)
283
 
284
        // The status register must be saved here, since loading a thread
285
        // context always involves an rte instruction. The details are
286
        // variant-specific.
287
        hal_context_pcsr_save_sr %sp,0,%d0
288
 
289
        // Now the fpu and other contexts can be saved. All registers
290
        // are available.
291
        hal_context_fpu_save_callee
292
        hal_context_other_save_callee
293
#else
294
        movem.l %d0-%d7/%a0-%a6, hal_context_integer_offset(%sp)
295
        hal_context_pcsr_save_sr %sp,0,%d0
296
        hal_context_fpu_save_all
297
        hal_context_other_save_all
298
#endif
299
 
300
        // All thread state has now been saved, so switch to the new one.
301
        mov.l   (hal_context_size+4)(%sp),%sp
302
 
303
#ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
304
        hal_context_other_load_callee
305
        hal_context_fpu_load_callee
306
        movem.l hal_context_integer_d2_offset(%sp),%d2-%d7
307
        movem.l hal_context_integer_a2_offset(%sp),%a2-%a6
308
#else
309
        hal_context_other_load_all
310
        hal_context_fpu_load_all
311
        movem.l hal_context_integer_offset(%sp),%d0-%d7/%a0-%a6
312
#endif
313
 
314
        add.l   #hal_context_rte_adjust, %sp
315
        rte
316
 
317
// ----------------------------------------------------------------------------
318
// setjmp()/longjmp(). See hal_arch.h for details.
319
//
320
// int  hal_m68k_setjmp(hal_jmp_buf);
321
// void hal_m68k_longjmp(hal_jmp_buf, val)
322
 
323
        FUNC_START_WEAK(hal_m68k_setjmp)
324
        lea.l       4(%sp),%a1                  // return stack pointer. longjmp() does an indirect jmp, not an rts
325
        move.l      0(%a1),%a0                  // the jmp_buf structure
326
        move.l      0(%sp),0(%a0)               // return pc
327
        move.l      %a1,4(%a0)
328
        movem.l     %d2-%d7/%a2-%a6,8(%a0)      // 11 longs, occupying offsets 8 to 51
329
#ifdef CYGINT_HAL_M68K_VARIANT_FPU
330
        fmovem.x    %fp2-%fp7,52(%a0)
331
#endif
332
        clr.l   %d0                             // setjmp() always returns 0
333
        rts
334
 
335
        FUNC_START_WEAK(hal_m68k_longjmp)
336
        move.l      8(%sp),%d0                  // val argument, and hence return value
337
        move.l      4(%sp),%a0                  // The jmp_buf structure
338
        movem.l     8(%a0),%d2-%d7/%a2-%a6
339
#ifdef CYGINT_HAL_M68K_VARIANT_FPU
340
        fmovem.x    52(%a0),%fp2-%fp7
341
#endif
342
        move.l      0(%a0),%a1                  // The return pc
343
        move.l      4(%a0),%sp
344
        jmp         (%a1)
345
 
346
// ----------------------------------------------------------------------------
347
// Synchronous exceptions. Interrupts are disabled because that could confuse
348
// some code like gdb stubs (breakpoints also involve synchronous exceptions).
349
// Full state is saved on the current stack, then usually we switch to the
350
// interrupt stack and handle the rest of the exception there. That avoids
351
// having to worry about gdb stubs stack requirements in every thread context.
352
//
353
// It is assumed that on entry there is pc/sr context information already
354
// on the stack. Some or all of this will have been provided by the hardware.
355
// Other bits, e.g. the specific exception number, may have been pushed by
356
// software that then jumped here. The hardware may also have pushed some
357
// additional state which has already been removed or stashes elsewhere,
358
// to keep things simple.
359
 
360
        .extern hal_m68k_exception_handler
361
 
362
        FUNC_START(hal_m68k_exception_vsr)
363
        mov.w   #0x2700, %sr
364
        sub.l   #hal_context_pcsr_offset, %sp
365
 
366
        // If CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT is enabled
367
        // then only caller-save registers need to be saved here, but
368
        // exceptions should be rare and the additional info may prove
369
        // useful to higher-level code.
370
        movem.l %d0-%d7/%a0-%a6, hal_context_integer_offset(%sp)
371
        hal_context_fpu_save_all
372
        hal_context_other_save_all
373
 
374
        // Remember the current stack pointer in a callee-save register,
375
        // which have all been saved anyway. That makes it easier to restore
376
        // the stack later.
377
        move.l  %sp,%a2
378
 
379
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
380
        // Do we need to switch to the interrupt stack?
381
        cmpa.l  _HAL_M68K_INTERRUPT_STACK_, %sp
382
        jbgt    1f
383
        cmpa.l  _HAL_M68K_INTERRUPT_STACK_BASE_, %sp
384
        jbge    2f
385
1:
386
        mova.l  _HAL_M68K_INTERRUPT_STACK_, %sp
387
2:
388
#endif
389
        // Zero out the frame pointer to encourage GDB to backtrace correctly
390
        suba.l  %a6, %a6
391
 
392
        // Now call into C with a single argument, the HAL_SavedRegisters
393
        mov.l   %a2,-(%sp)
394
        jbsr    hal_m68k_exception_handler
395
 
396
        // We can switch back to the right stack by re-using a2, irrespective
397
        // of whether or not we switched to the interrupt stack.
398
        move.l  %a2,%sp
399
 
400
        // Restore the entire state. In theory only the callee-save registers
401
        // should have changed, but some others may have been manipulated by
402
        // gdb.
403
        hal_context_other_load_all
404
        hal_context_fpu_load_all
405
        movem.l hal_context_integer_offset(%sp), %d0-%d7/%a0-%a6
406
        add.l   #hal_context_rte_adjust, %sp
407
        rte
408
 
409
// ----------------------------------------------------------------------------
410
// Interrupt handling.
411
//
412
// The current stack may be a thread stack or the interrupt stack.
413
// On some variants this code will be called directly by the hardware.
414
// On others there will have been a trampoline doing some stack
415
// manipulation and then jumping here. We assume that the stack is
416
// properly aligned and that the pc/sr part has been correctly saved.
417
 
418
        FUNC_START(hal_m68k_interrupt_vsr)
419
 
420
#ifndef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
421
        // If nesting is not of interest then just disable all interrupts.
422
        // Otherwise interrupt nesting is controlled via the M68K IPL
423
        move.w  #0x2700, %sr
424
#endif
425
 
426
        sub.l   # hal_context_pcsr_offset, %sp
427
#ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
428
        // Even for a minimum context the callee-save a2 register
429
        // is saved. This makes it easier to restore the stack
430
        // to the right place after the ISR call, allowing for
431
        // the optional interrupt stack.
432
        movem.l %d0-%d1,hal_context_integer_d0_offset(%sp)
433
        movem.l %a0-%a2,hal_context_integer_a0_offset(%sp)
434
        hal_context_fpu_save_caller %sp
435
        hal_context_other_save_caller %sp
436
#else
437
        movem.l %d0-%d7/%a0-%a6, hal_context_integer_d0_offset(%sp)
438
        hal_context_fpu_save_all %sp
439
        hal_context_other_save_all %sp
440
#endif
441
 
442
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
443
        // Let gdb stubs know which thread was interrupted, in case this
444
        // interrupt was a ctrl-C.
445
        .extern hal_saved_interrupt_state
446
        move.l  %sp, hal_saved_interrupt_state
447
#endif
448
 
449
        // d0/d1/a0/a1/a2 are now available.
450
        // We want to extract the ISR vector while it is readily accessible.
451
        // The details depend the particular M68K variant. The result should
452
        // be the vector << 2 to facilitate indexing. On some processors that
453
        // actually requires less code than getting the vector itself.
454
        hal_context_extract_isr_vector_shl2 %sp,0,%d0
455
 
456
#if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
457
        // We need to call cyg_instrument(INTR.RAISE, vector, intr_number)
458
        // The actual interrupt number is not readily available, it depends
459
        // on the variant and possibly the platform, so just instrument 0
460
        // instead. The vector is preserved in callee-save a2 since it may
461
        // take several instructions to refetch it.
462
        movea.l %d0, %a2
463
        lsr.l   #2, %d0
464
        move.l  #0, -(%sp)
465
        move.l  %d0, -(%sp)
466
        move.l  #0x0301, -(%sp)
467
        jbsr    cyg_instrument
468
        add.l   #12, %sp
469
        move.l  %a2, %d0
470
#endif
471
 
472
        // %d0 holds the ISR vector << 2. d1/a0/a1/a2 are available.
473
 
474
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
475
        // Increment the scheduler lock. In theory the ISR should not look
476
        // at this so it could be deferred till just before the interrupt_end()
477
        // call, but this provides protection against badly written ISR's.
478
        //
479
        // This is not sufficient on SMP systems. The test of the scheduler lock
480
        // below also needs attention.
481
        .extern cyg_scheduler_sched_lock
482
        addq.l  #1, cyg_scheduler_sched_lock
483
#endif
484
 
485
        // At the end of the VSR we need to call interrupt_end().
486
        // The last two arguments are cyg_hal_interrupt_objects[vec]
487
        // and the saved registers. These are pushed now, while
488
        // vec is readily available, at the cost of a slight increase
489
        // in interrupt latency but saving some instructions later.
490
        move.l  %sp,-(%sp)
491
        lea     cyg_hal_interrupt_objects,%a0
492
        move.l  0(%a0,%d0), -(%sp)
493
 
494
        // We want to be able to restore the stack pointer to this location,
495
        // irrespective of whether or not an interrupt stack is being used.
496
        // Store it in a callee-save register.
497
        movea.l %sp, %a2
498
 
499
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
500
        // Switch to the interrupt stack if we are not already running there.
501
        cmpa.l  _HAL_M68K_INTERRUPT_STACK_, %sp
502
        jbgt    1f
503
        cmpa.l  _HAL_M68K_INTERRUPT_STACK_BASE_, %sp
504
        jbge    2f
505
1:
506
        movea.l _HAL_M68K_INTERRUPT_STACK_, %sp
507
2:
508
#endif
509
        // FIXME: Some variation of the following should be considered to ensure that
510
        // GDB can't get permanently lost when doing a backtrace from within an ISR.
511
#if 0 && defined(CYGPKG_INFRA_DEBUG) && !defined(CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT)
512
        // Zero out the frame pointer to encourage GDB to backtrace correctly
513
        // But only if explicitly debugging so that we don't adversely affect
514
        // critical ISR latency
515
        move.w  #0,%a6
516
#endif
517
 
518
        // d0 is the isr vector << 2. a2 holds a saved stack pointer. d1/a0/a1 are available.
519
        // We need to call (*cyg_hal_interrupt_handlers[vec])(vec, cyg_hal_interrupt_data[vec])
520
        lea     cyg_hal_interrupt_data,%a0
521
        move.l  0(%a0,%d0),-(%sp)
522
        lea     cyg_hal_interrupt_handlers,%a0
523
        move.l  0(%a0,%d0),%a1
524
        lsr.l   #2,%d0
525
        move.l  %d0,-(%sp)
526
        jbsr    (%a1)
527
 
528
        // We now want to return to the right position on the current
529
        // stack, or to the thread stack if we switched to the interrupt
530
        // stack.
531
        movea.l %a2, %sp
532
 
533
        // Next we need to call interrupt_end(). If the scheduler was unlocked
534
        // at the time of the interrupt then that will run the DSRs, possibly
535
        // cause a context switch, and eventually return to this VSR. If the
536
        // scheduler was already locked then interrupt_end() will return to
537
        // the VSR almost immediately. The IPL level will be restored when
538
        // the VSR executes the final rte.
539
        //
540
        // DSRs should run with interrupts re-enabled. Ideally we want to
541
        // run them with the IPL level of the interrupted thread, and at
542
        // the end reset the IPL level to what it is now. That way this
543
        // VSR gets to return, without risk of unconstrained stack usage.
544
        // However this is very hard: currently the desired IPL levels
545
        // cannot be passed on the stack; they cannot be passed via globals
546
        // either because of the possibility of a context switch.
547
        //
548
        // Instead there is a defined IPL level for running all DSRs.
549
        // HAL_INTERRUPT_STACK_CALL_PENDING_DSRs() sets the IPL level to
550
        // that value, and restores the IPL level when done. For most
551
        // applications that will be fine, but it does make it more
552
        // difficult to manipulate IPL levels on a per-thread level
553
        // or anything similarly fancy.
554
 
555
        // We need to call interrupt_end(isr_return, cyg_hal_interrupt_objects[vec], saved_state_pointer)
556
        // The last two have already been pushed onto the stack. d0 holds the return value.
557
        move.l  %d0,-(%sp)
558
        jbsr    interrupt_end
559
        add.l   #12,%sp
560
 
561
#ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
562
        hal_context_other_load_caller %sp
563
        hal_context_fpu_load_caller %sp
564
        movem.l hal_context_integer_a0_offset(%sp),%a0-%a2
565
        movem.l hal_context_integer_d0_offset(%sp),%d0-%d1
566
#else
567
        hal_context_other_load_all %sp
568
        hal_context_fpu_load_all   %sp
569
        movem.l hal_context_integer_d0_offset(%sp),%d0-%d7/%a0-%a6
570
#endif
571
        add.l   #hal_context_rte_adjust,%sp
572
        rte
573
 
574
// ----------------------------------------------------------------------------
575
// On configurations with an interrupt stack HAL_INTERRUPT_STACK_CALL_PENDING_DSRS()
576
// is used to run the DSRs on the interrupt stack rather than the thread stack,
577
// reducing stack size requirements for the latter. It is called only on a thread
578
// stack. In addition to the stack switch the IPL level is manipulated here,
579
// ensuring that DSRs run with interrupts enabled.
580
//
581
// On other architectures HAL_INTERRUPT_STACK_CALL_PENDING_DSRS() is only called
582
// when a separate interrupt stack is used. If the interrupt stack is disabled
583
// then DSRs run with interrupts disabled, which is a bad idea. On the M68K
584
// HAL_INTERRUPT_STACK_CALL_PENDING_DSRS() is always defined, thus sorting out
585
// the interrupt level, but only does the stack switch if an interrupt stack
586
// is actually being used.
587
 
588
        .extern hal_m68k_dsr_ipl_level
589
        .extern cyg_interrupt_call_pending_DSRs
590
 
591
        FUNC_START(hal_interrupt_stack_call_pending_DSRs)
592
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
593
        // Use callee-save registers to store the current stack and status register
594
        // Also store the frame pointer so we can zero it to improve GDB debugging backtraces
595
        move.l  %a2,-(%sp)
596
        move.l  %d2,-(%sp)
597
        move.l  %a6,-(%sp)
598
        movea.l %sp,%a2
599
        move.w  %sr,%d2
600
        suba.l  %a6,%a6
601
 
602
        // There is a problem if the configuration contains the kernel but interrupts
603
        // are enabled while still running the startup code. The kernel's interrupt_end()
604
        // rather than the driver API's will be used, so this code gets to run. We now
605
        // get to switch to the interrupt stack while still on the startup stack, which
606
        // is a shame since the two are the same. This could be easily fixed by checking
607
        // the current stack as happens in the interrupt_vsr, but at the cost of an
608
        // extra four instructions in the DSR path. The scenario should probably not
609
        // arise so those four instructions are left out for now.
610
        movea.l _HAL_M68K_INTERRUPT_STACK_, %sp
611
        move.l  hal_m68k_dsr_ipl_level, %d0
612
        move.w  %d0, %sr
613
 
614
        jbsr    cyg_interrupt_call_pending_DSRs
615
 
616
        move.w  %d2, %sr
617
        movea.l %a2, %sp
618
        movea.l (%sp)+,%a6
619
        move.l  (%sp)+,%d2
620
        movea.l (%sp)+,%a2
621
        rts
622
#else
623
        move.l  %d2, -(%sp)
624
        move.w  %sr, %d2
625
        move.l  hal_m68k_dsr_ipl_level, %d0
626
        move.w  %d0, %sr
627
        jbsr    cyg_interrupt_call_pending_DSRs
628
        move.w  %d2, %sr
629
        move.l  (%sp)+, %d2
630
        rts
631
#endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
632
 
633
 
634
// ----------------------------------------------------------------------------
635
// A dummy entry point for unused entries in the system exception vector.
636
 
637
        FUNC_START(hal_m68k_rte)
638
        rte
639
 
640
// ----------------------------------------------------------------------------
641
// Fast implementations of lsbit_index() and msbit_index()
642
 
643
        FUNC_START(hal_lsbit_index)
644
        clr.l   %d0                     // result
645
        mov.l   4(%sp),%d1              // mask
646
        bne     1f                      // special case for 0
647
        subq.l  #1,%d0                  // lsbit_index(0) -> -1
648
        rts
649
1:
650
        tst.w   %d1                     // anything set in the bottom 16 bits?
651
        bne     2f
652
        swap    %d1                     // the top 16 bits only are of interest
653
        moveq.l #16, %d0
654
2:
655
        tst.b   %d1                     // anything set in the bottom 8 bits?
656
        bne     3f
657
        addq.l  #8, %d0                 // bottom byte is 0, switch to next byte
658
        lsr.l    #8, %d1
659
3:
660
        move.l  %d1, %a0                // backup current data, so that we can manipulate it
661
        and.l   #0x0F, %d1              // anything in the bottom nibble?
662
        bne     4f
663
        move.l  %a0, %d1                // nope, restore and use the next nibble
664
        lsr.l    #4, %d1
665
        and.l   #0x0F, %d1
666
        addq.l  #4, %d0
667
4:
668
                                        // The bottom nibble contains a number between 1 and 15
669
                                        // (not 0, that would have been caught by the test at the top).
670
        lea     5f, %a0
671
        mov.b   0(%a0,%d1),%d1          // only zap bottom byte, the other bytes are already 0
672
        add.l   %d1,%d0
673
        rts
674
5:
675
        // Every odd number has an index of 0. The first entry is irrelevent.
676
        .byte 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
677
 
678
        FUNC_START(hal_msbit_index)
679
        clr.l   %d0                     // result
680
        mov.l   4(%sp), %d1             // mask
681
        bne     1f                      // special case for 0
682
        subq.l  #1, %d0                 // msbit_index(0) -> -1
683
        rts
684
1:
685
        cmpi.l  #0x0000FFFF,%d1
686
        bls     2f
687
        moveq.l #16,%d0
688
        clr.w   %d1
689
        swap    %d1
690
2:
691
        cmpi.l  #0x00FF, %d1
692
        bls     3f
693
        addq.l  #8, %d0
694
        lsr.l   #8, %d1
695
3:
696
        cmpi.l  #0x000F, %d1
697
        bls     4f
698
        addq.l  #4, %d0
699
        lsr.l   #4, %d1
700
 
701
4:
702
        lea     5f, %a0
703
        mov.b   0(%a0,%d1), %d1
704
        add.l   %d1,%d0
705
        rts
706
 
707
5:
708
        .byte 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
709
 
710
// ----------------------------------------------------------------------------
711
// Profiling support. When code is compiled with -pg the compiler inserts
712
// calls to mcount() at the start of each function. This can be used to
713
// build a callgraph of the application. mcount() is tied to the compiler
714
// internals and does not always use standard calling conventions.
715
//
716
// mcount() should call __profile_mcount() with two arguments, caller_pc
717
// and callee_pc, where callee_pc refers to the function that calls
718
// mcount() and caller_pc refers to the place where that function is
719
// called from. callee_pc is readily accessed relative to sp, caller_pc
720
// can be accessed using the frame pointer. This assumes the code has
721
// not been built with -fomit-frame-pointer, a safe assumption since
722
// the compiler disallows combining -pg and -fomit-frame-pointer.
723
//
724
// The m68k compiler appears to implement mcount() a bit differently
725
// from other targets. It reserves a word for every function entry
726
// point which presumably is intended to act as the start of a linked
727
// list chain. On other targets the PC is used to index a hash table
728
// which contains the start of that linked list. That extra word is
729
// not used for eCos profiling since it would require customizing the
730
// profiling package on a per-target basis, so unfortunately the
731
// memory is wasted.
732
//
733
// It is assumed that d0/d1/a0/a1 (the callee-save registers) are
734
// available. a0 is certainly available because that is used to hold
735
// the above per-function word. If the assumption is false then this
736
// would have to save d0/d1/a1 because the C __profile_mcount() could
737
// zap them.
738
//
739
// This code is conditional on CYGPKG_PROFILE_GPROF since that provides
740
// the implementation of __profile_mcount.
741
#ifdef CYGPKG_PROFILE_GPROF
742
        FUNC_START(mcount)
743
        // __profile_mcount() should be called with interrupts disabled.
744
        move.w  %sr,%d0
745
        move.l  %d0,-(%sp)
746
        // The callee-pc corresponds to the return address on the stack
747
        move.l  4(%sp),%a0
748
        move.l  %a0,-(%sp)
749
        // The caller-pc is accessible relative to the frame pointer a6
750
        move.l  4(%a6),%a0
751
        move.l  %a0,-(%sp)
752
 
753
        move.w  #0x2700, %sr
754
        jbsr    __profile_mcount
755
 
756
        move.l  8(%sp),%d0
757
        add.l   #12, %sp
758
        move.w  %d0,%sr
759
 
760
        rts
761
#endif
762
 
763
        .end

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.