📄 vectors.s
字号:
| Call spurious interrupt handler
.extern hal_spurious_interrupt
jsr hal_spurious_interrupt
| Remove the arguments from the stack.
addq.l #4,%sp
| Restore the preserved registers for the current thread.
int_rest_regs
#endif /* ifndef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS */
| Just return from interrupt.
rte
| ----------------------------------------------------------------------------
| User interrupt vector handler
|
| Control is transferred here from a user interrupt vector (#64-255).
| Before branching to common code, load a value to translate the
| vector table offset to the ISR table offset.
.text
.balign 4
.globl cyg_hal_default_interrupt_vsr
cyg_hal_default_interrupt_vsr:
| Disable all interrupts. On the first instruction, interrupt sampling
| is always disabled.
hal_cpu_int_disable
| Preserve all registers that this handler needs to preserve.
| The C code will preserve all other registers.
int_pres_regs
| It is safe to use breakpoints below this point.
.globl _cyg_hal_default_interrupt_vsr_bp_safe
_cyg_hal_default_interrupt_vsr_bp_safe:
| Adding this value to the vector table offset will result in the
| corresponding offset into the ISR table.
move.l #(-CYGNUM_HAL_ISR_MIN)*4,%d2
| d2.l: Contains a value to translate the vector table offset to
| the ISR table offset.
| Calculate the vector offset. The format/vector word on the stack
| contains the vector number. Mask off all unused bits. The bit
| position of the vector number field makes it automatically multiplied
| by four.
move.w CYGARC_CF_FMTVECWORD(%sp),%d1
and.l #0x000003fc,%d1
| Calculate the ISR table offset. Add the vector table offset to the
| translation value.
add.l %d1,%d2
| Calculate the vector number using the vector table offset.
asr.l #2,%d1
| d2.l: Contains the offset into the ISR table.
| d1.l: Contains the vector number.
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
|| defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
| If we are supporting Ctrl-C interrupts from GDB, we must squirrel
| away a pointer to the saved interrupt state here so that we can
| plant a breakpoint at some later time.
.extern hal_saved_interrupt_state
move.l %sp,(hal_saved_interrupt_state)
#endif
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
| Lock the scheduler if we are using the kernel.
.extern cyg_scheduler_sched_lock
addq.l #1,cyg_scheduler_sched_lock
#endif /* CYGFUN_HAL_COMMON_KERNEL_SUPPORT */
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
| a0 = sp. We'll need it later
move.l %sp,%a0
cmp.l #__interrupt_stack_base,%sp
| If sp < base : not on istack
blt 1f
cmp.l #__interrupt_stack,%sp
| If sp <= top : already on istack
ble 2f
1:
| Switch to istack
lea __interrupt_stack,%sp
2:
| Save old SP on istack
pea (%a0)
#endif
#if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
.extern cyg_instrument
| Save d1
move.l %d1,-(%sp)
| arg2 = 0
move.l #0,-(%sp)
| arg1 = vector number
move.l %d1,-(%sp)
| type = INTR,RAISE
move.l #0x0301,-(%sp)
| Call instrumentation
jsr cyg_instrument
| Remove args from stack
add.l #12,%sp
| Restore %d1
move.l (%sp)+,%d1
#endif
#ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
| If interrupt nesting is enabled, we have to determine the IPL of the
| current interrupt. We inline the following macro, which is defined
| by ColdFire variants. The vector number of the current interrupt
| is passed in d0, and the return value is in d0.
| Registers a0-a1/d0-d1 are for use by the macro, other registers
| must be saved explicitly before being used.
| Save %d1
move.l %d1,-(%sp)
| Pass d1 as argument to macro
move.l %d1,%d0
| Retrieve IPL, which will be contained in d0
hal_variant_retrieve_ipl
| Shift IPL up to the same position occupied in sr
lsl.l #8,%d0
| Transform d0 in a mask to be applied to sr
or.l #0xfffff0ff,%d0
| Update sr. Use d1 as working register
move.w %sr,%d1
and.l %d0,%d1
move.w %d1,%sr
| Restore d1
move.l (%sp)+,%d1
#endif
| We need to call the following routines. The isr address, data, and
| intr are all from the ISR table. The interrupt_end routine is
| only called if we are using the kernel. regs points to the saved
| registers on the stack. isr_ret is the return value from the ISR.
| vector is the vector number.
| static cyg_uint32 isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
| externC void interrupt_end(cyg_uint32 isr_ret, Cyg_Interrupt *intr,
| HAL_SavedRegisters *regs)
| Push the data value from the table.
.extern cyg_hal_interrupt_data
lea cyg_hal_interrupt_data,%a0
move.l (%a0,%d2.l),-(%sp)
| Get the address of the ISR from the table.
.extern cyg_hal_interrupt_handlers
lea cyg_hal_interrupt_handlers,%a0
move.l (%a0,%d2.l),%a0
| Push the vector number parameter.
move.l %d1,-(%sp)
| Call the ISR.
jsr (%a0)
| Remove the isr parameters from the stack.
addq.l #4*2,%sp
| d0.l now contains the return value from the ISR.
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
| If we are returning from the last nested interrupt, move back
| to the thread stack. interrupt_end() must be called on the
| thread stack since it potentially causes a context switch.
| Since we have arranged for the top of stack location to
| contain the sp we need to go back to here, just pop it off
| and put it in SP.
move.l (%sp),%sp | sp = *sp
#endif
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
| We only need to call interrupt_end() when there is a kernel
| present to do any tidying up. To keep the following code simple,
| we enable all interrupts before calling DSRs only if a common
| interrupt stack is in use.
| Push the regs pointer.
pea (%sp)
| Push the intr object pointer from the table.
.extern cyg_hal_interrupt_objects
lea cyg_hal_interrupt_objects,%a0
move.l (%a0,%d2.l),-(%sp)
| Push ISR return value
move.l %d0,-(%sp)
| Even when this is not the last nested interrupt, we must call
| interrupt_end() to post the DSR and decrement the scheduler
| lock.
| Call the interrupt_end C routine.
.extern interrupt_end
jsr interrupt_end
| Remove the isr_ret, intr, and regs parameters from the stack.
lea (4*3)(%sp),%sp
#endif /* ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT */
| Restore the preserved registers for the current thread.
int_rest_regs
| Restore the SR and PC.
rte
| ----------------------------------------------------------------------------
| Execute pending DSRs on the interrupt stack with interrupts enabled.
| Note: this can only be called from code running on a thread stack
#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
.extern cyg_interrupt_call_pending_DSRs
FUNC_START(hal_interrupt_stack_call_pending_DSRs)
| Change to interrupt stack, save state and set up stack for
| calls to C code.
| By virtue of GNU C calling conventions, we are free to use registers
| %d0-%d1 and %a0-%a1 without saving them.
| a0 = sp
move.l %sp, %a0
| Switch to istack
lea __interrupt_stack,%sp
| Save old SP on istack
pea (%a0)
| Save sr
move.w %sr,%d0
move.l %d0,-(%sp)
| Enable interrupts
hal_cpu_int_enable %d0
| Call into kernel which will execute DSRs
jsr cyg_interrupt_call_pending_DSRs
move.l (%sp)+,%d0
| Restore previous interrupt state
hal_cpu_int_merge %d0,%d1
| Restore sp
move.l (%sp),%sp
| return to caller
rts
#endif
| ----------------------------------------------------------------------------
| Interrupt and reset stack
|
| WARNING: Do not put this in any memory section that gets initialized.
| Doing so may cause the C code to initialize its own stack.
.section ".uninvar","aw",@nobits
.balign 16
.global cyg_interrupt_stack_base
cyg_interrupt_stack_base:
__interrupt_stack_base:
.skip CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
.balign 16
.global cyg_interrupt_stack
cyg_interrupt_stack:
__interrupt_stack:
.skip 0x10
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -