⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpu_asm.s

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 S
📖 第 1 页 / 共 2 页
字号:
/*  cpu_asm.s * *  This file contains the basic algorithms for all assembly code used *  in an specific CPU port of RTEMS.  These algorithms must be implemented *  in assembly language.  * *  COPYRIGHT (c) 1989-1999. *  On-Line Applications Research Corporation (OAR). * *  The license and distribution terms for this file may be *  found in the file LICENSE in this distribution or at *  http://www.rtems.com/license/LICENSE. * *  Ported to ERC32 implementation of the SPARC by On-Line Applications *  Research Corporation (OAR) under contract to the European Space  *  Agency (ESA). * *  ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995.  *  European Space Agency. * *  $Id: cpu_asm.S,v 1.8.2.3 2005/10/05 19:30:18 joel Exp $ */#include <asm.h>/* *  void _CPU_Context_initialize_fp( *    void *fp_context_ptr *  ) * *  This routine is responsible for initializing the FP context *  at *fp_context_ptr. All registers and FSR in the FP context *  are initailized to 0.   *   */        .align 4        PUBLIC(_CPU_Context_initialize_fp)SYM(_CPU_Context_initialize_fp):	set	0, %l1fpcontextinit:		std	%g0, [%o0]		! write register fields of the FP context	add	%l1, 1, %l1	cmp	%l1, 16	bne	fpcontextinit								add	%o0, 8, %o0	retl			st	%g0, [%o0]		! write fsr field of the FP context			/* *  void _CPU_Context_save_fp( *    void **fp_context_ptr *  ) * *  This routine is responsible for saving the FP context *  at *fp_context_ptr.  If the point to load the FP context *  from is changed then the pointer is modified by this routine. * *  NOTE: See the README in this directory for information on the  *        management of the "EF" bit in the PSR. */        .align 4        PUBLIC(_CPU_Context_save_fp)SYM(_CPU_Context_save_fp):        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp        /*         *  The following enables the floating point unit.         */           mov     %psr, %l0        sethi   %hi(SPARC_PSR_EF_MASK), %l1        or      %l1, %lo(SPARC_PSR_EF_MASK), %l1        or      %l0, %l1, %l0        mov     %l0, %psr                  ! **** ENABLE FLOAT ACCESS ****	nop; nop; nop;			   ! Need three nops before EF is         ld      [%i0], %l0		   ! active due to pipeline delay!!!        std     %f0, [%l0 + FO_F1_OFFSET]        std     %f2, [%l0 + F2_F3_OFFSET]        std     %f4, [%l0 + F4_F5_OFFSET]        std     %f6, [%l0 + F6_F7_OFFSET]        std     %f8, [%l0 + F8_F9_OFFSET]        std     %f10, [%l0 + F1O_F11_OFFSET]        std     %f12, [%l0 + F12_F13_OFFSET]        std     %f14, [%l0 + F14_F15_OFFSET]        std     %f16, [%l0 + F16_F17_OFFSET]        std     %f18, [%l0 + F18_F19_OFFSET]        std     %f20, [%l0 + F2O_F21_OFFSET]        std     %f22, [%l0 + F22_F23_OFFSET]        std     %f24, [%l0 + F24_F25_OFFSET]        std     %f26, [%l0 + F26_F27_OFFSET]        std     %f28, [%l0 + F28_F29_OFFSET]        std     %f30, [%l0 + F3O_F31_OFFSET]        st      %fsr, [%l0 + FSR_OFFSET]        ret        restore/* *  void _CPU_Context_restore_fp( *    void **fp_context_ptr *  ) * *  This routine is responsible for restoring the FP context *  at *fp_context_ptr.  If the point to load the FP context *  from is changed then the pointer is modified by this routine. * *  NOTE: See the README in this directory for information on the  *        management of the "EF" bit in the PSR. */        .align 4        PUBLIC(_CPU_Context_restore_fp)SYM(_CPU_Context_restore_fp):        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE , %sp        /*         *  The following enables the floating point unit.         */           mov     %psr, %l0        sethi   %hi(SPARC_PSR_EF_MASK), %l1        or      %l1, %lo(SPARC_PSR_EF_MASK), %l1        or      %l0, %l1, %l0        mov     %l0, %psr                  ! **** ENABLE FLOAT ACCESS ****	nop; nop; nop;			   ! Need three nops before EF is         ld      [%i0], %l0		   ! active due to pipeline delay!!!        ldd     [%l0 + FO_F1_OFFSET], %f0        ldd     [%l0 + F2_F3_OFFSET], %f2        ldd     [%l0 + F4_F5_OFFSET], %f4        ldd     [%l0 + F6_F7_OFFSET], %f6        ldd     [%l0 + F8_F9_OFFSET], %f8        ldd     [%l0 + F1O_F11_OFFSET], %f10        ldd     [%l0 + F12_F13_OFFSET], %f12        ldd     [%l0 + F14_F15_OFFSET], %f14        ldd     [%l0 + F16_F17_OFFSET], %f16        ldd     [%l0 + F18_F19_OFFSET], %f18        ldd     [%l0 + F2O_F21_OFFSET], %f20        ldd     [%l0 + F22_F23_OFFSET], %f22        ldd     [%l0 + F24_F25_OFFSET], %f24        ldd     [%l0 + F26_F27_OFFSET], %f26        ldd     [%l0 + F28_F29_OFFSET], %f28        ldd     [%l0 + F3O_F31_OFFSET], %f30        ld      [%l0 + FSR_OFFSET], %fsr        ret        restore/* *  void _CPU_Context_switch( *    Context_Control  *run, *    Context_Control  *heir *  ) * *  This routine performs a normal non-FP context switch. */        .align 4        PUBLIC(_CPU_Context_switch)SYM(_CPU_Context_switch):        ! skip g0        st      %g1, [%o0 + G1_OFFSET]       ! save the global registers        std     %g2, [%o0 + G2_OFFSET]        std     %g4, [%o0 + G4_OFFSET]        std     %g6, [%o0 + G6_OFFSET]        std     %l0, [%o0 + L0_OFFSET]       ! save the local registers        std     %l2, [%o0 + L2_OFFSET]        std     %l4, [%o0 + L4_OFFSET]        std     %l6, [%o0 + L6_OFFSET]        std     %i0, [%o0 + I0_OFFSET]       ! save the input registers        std     %i2, [%o0 + I2_OFFSET]        std     %i4, [%o0 + I4_OFFSET]        std     %i6, [%o0 + I6_FP_OFFSET]        std     %o0, [%o0 + O0_OFFSET]       ! save the output registers        std     %o2, [%o0 + O2_OFFSET]        std     %o4, [%o0 + O4_OFFSET]        std     %o6, [%o0 + O6_SP_OFFSET]        rd      %psr, %o2        st      %o2, [%o0 + PSR_OFFSET]      ! save status register        /*         *  This is entered from _CPU_Context_restore with:         *    o1 = context to restore         *    o2 = psr         */        PUBLIC(_CPU_Context_restore_heir)SYM(_CPU_Context_restore_heir):        /*         *  Flush all windows with valid contents except the current one.         *  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 -- 6 and 7.         *         *   Traps are disabled for the same logical period as in a          *     flush all windows trap handler.         *            *    Register Usage while saving the windows:         *      g1 = current PSR         *      g2 = current wim         *      g3 = CWP         *      g4 = wim scratch         *      g5 = scratch         */        ld      [%o1 + PSR_OFFSET], %g1       ! g1 = saved psr        and     %o2, SPARC_PSR_CWP_MASK, %g3  ! g3 = CWP                                              ! g1 = psr w/o cwp        andn    %g1, SPARC_PSR_ET_MASK | SPARC_PSR_CWP_MASK, %g1        or      %g1, %g3, %g1                 ! g1 = heirs psr        mov     %g1, %psr                     ! restore status register and                                              ! **** DISABLE TRAPS ****        mov     %wim, %g2                     ! g2 = wim        mov     1, %g4        sll     %g4, %g3, %g4                 ! g4 = WIM mask for CW invalidsave_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        nopdone_flushing:        add     %g3, 1, %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        or      %g1, SPARC_PSR_ET_MASK, %g1        mov     %g1, %psr                     ! **** ENABLE TRAPS ****                                              !   and restore CWP        nop        nop        nop        ! skip g0        ld      [%o1 + G1_OFFSET], %g1        ! restore the global registers        ldd     [%o1 + G2_OFFSET], %g2        ldd     [%o1 + G4_OFFSET], %g4        ldd     [%o1 + G6_OFFSET], %g6        ldd     [%o1 + L0_OFFSET], %l0        ! restore the local registers        ldd     [%o1 + L2_OFFSET], %l2        ldd     [%o1 + L4_OFFSET], %l4        ldd     [%o1 + L6_OFFSET], %l6        ldd     [%o1 + I0_OFFSET], %i0        ! restore the output registers        ldd     [%o1 + I2_OFFSET], %i2        ldd     [%o1 + I4_OFFSET], %i4        ldd     [%o1 + I6_FP_OFFSET], %i6        ldd     [%o1 + O2_OFFSET], %o2        ! restore the output registers        ldd     [%o1 + O4_OFFSET], %o4        ldd     [%o1 + O6_SP_OFFSET], %o6        ! do o0/o1 last to avoid destroying heir context pointer        ldd     [%o1 + O0_OFFSET], %o0        ! overwrite heir pointer        jmp     %o7 + 8                       ! return        nop                                   ! delay slot/* *  void _CPU_Context_restore( *    Context_Control *new_context *  ) * *  This routine is generally used only to perform restart self. * *  NOTE: It is unnecessary to reload some registers. */        .align 4        PUBLIC(_CPU_Context_restore)SYM(_CPU_Context_restore):        save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp        rd      %psr, %o2        ba      SYM(_CPU_Context_restore_heir)        mov     %i0, %o1                      ! in the delay slot/* *  void _ISR_Handler() * *  This routine provides the RTEMS interrupt management. * *  We enter this handler from the 4 instructions in the trap table with *  the following registers assumed to be set as shown: * *    l0 = PSR *    l1 = PC *    l2 = nPC *    l3 = trap type * *  NOTE: By an executive defined convention, trap type is between 0 and 255 if *        it is an asynchonous trap and 256 and 511 if it is synchronous. */        .align 4        PUBLIC(_ISR_Handler)SYM(_ISR_Handler):        /*         *  Fix the return address for synchronous traps.         */        andcc   %l3, SPARC_SYNCHRONOUS_TRAP_BIT_MASK, %g0                                      ! Is this a synchronous trap?        be,a    win_ovflow            ! No, then skip the adjustment        nop                           ! DELAY        mov     %l1, %l6              ! save trapped pc for debug info        mov     %l2, %l1              ! do not return to the instruction        add     %l2, 4, %l2           ! indicatedwin_ovflow:        /*         *  Save the globals this block uses.         *         *  These registers are not restored from the locals.  Their contents         *  are saved directly from the locals into the ISF below.         */        mov     %g4, %l4                 ! save the globals this block uses        mov     %g5, %l5        /*         *  When at a "window overflow" trap, (wim == (1 << cwp)).         *  If we get here like that, then process a window overflow.         */        rd      %wim, %g4        srl     %g4, %l0, %g5            ! g5 = win >> cwp ; shift count and CWP                                         !   are LS 5 bits ; how convenient :)        cmp     %g5, 1                   ! Is this an invalid window?        bne     dont_do_the_window       ! No, then skip all this stuff        ! we are using the delay slot        /*         *  The following is same as a 1 position right rotate of WIM         */        srl     %g4, 1, %g5              ! g5 = WIM >> 1        sll     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4                                         ! g4 = WIM << (Number Windows - 1)        or      %g4, %g5, %g4            ! g4 = (WIM >> 1) |                                         !      (WIM << (Number Windows - 1))        /*         *  At this point:         *         *    g4 = the new WIM         *    g5 is free         */        /*         *  Since we are tinkering with the register windows, we need to         *  make sure that all the required information is in global registers.         */        save                          ! Save into the window        wr      %g4, 0, %wim          ! WIM = new WIM        nop                           ! delay slots        nop        nop        /*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -