📄 cpu_asm.s
字号:
/* 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 * * Author: Craig Lebakken <craigl@transition.com> * * COPYRIGHT (c) 1996 by Transition Networks Inc. * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file * for any purpose is hereby granted without fee, provided that * the above copyright notice and this notice appears in all * copies, and that the name of Transition Networks not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * Transition Networks makes no representations about the suitability * of this software for any purpose. * * Derived from source copyrighted as follows: * * 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. * * $Id: cpu_asm.S,v 1.8.4.1 2003/09/04 18:47:32 joel Exp $ *//* @(#)cpu_asm.S 08/20/96 1.15 */#include "cpu_asm.h"#include "iregdef.h"#include "idtcpu.h"#define FRAME(name,frm_reg,offset,ret_reg) \ .globl name; \ .ent name; \name:; \ .frame frm_reg,offset,ret_reg#define ENDFRAME(name) \ .end name#define EXCP_STACK_SIZE (NREGS*R_SZ)#if __ghs__#define sd sw#define ld lw#define dmtc0 mtc0#define dsll sll#define dmfc0 mfc0#endif#if 1 /* 32 bit unsigned32 types */#define sint sw#define lint lw#define stackadd addiu#define intadd addu#define SZ_INT 4#define SZ_INT_POW2 2#else /* 64 bit unsigned32 types */#define sint dw#define lint dw#define stackadd daddiu#define intadd daddu#define SZ_INT 8#define SZ_INT_POW2 3#endif#ifdef __GNUC__#define EXTERN(x,size) .extern x,size#else#define EXTERN(x,size)#endif/* NOTE: these constants must match the Context_Control structure in cpu.h */#define S0_OFFSET 0#define S1_OFFSET 1#define S2_OFFSET 2#define S3_OFFSET 3#define S4_OFFSET 4#define S5_OFFSET 5#define S6_OFFSET 6#define S7_OFFSET 7#define SP_OFFSET 8#define FP_OFFSET 9#define RA_OFFSET 10#define C0_SR_OFFSET 11#define C0_EPC_OFFSET 12/* NOTE: these constants must match the Context_Control_fp structure in cpu.h */#define FP0_OFFSET 0 #define FP1_OFFSET 1 #define FP2_OFFSET 2 #define FP3_OFFSET 3 #define FP4_OFFSET 4 #define FP5_OFFSET 5 #define FP6_OFFSET 6 #define FP7_OFFSET 7 #define FP8_OFFSET 8 #define FP9_OFFSET 9 #define FP10_OFFSET 10 #define FP11_OFFSET 11 #define FP12_OFFSET 12 #define FP13_OFFSET 13 #define FP14_OFFSET 14 #define FP15_OFFSET 15 #define FP16_OFFSET 16 #define FP17_OFFSET 17 #define FP18_OFFSET 18 #define FP19_OFFSET 19 #define FP20_OFFSET 20 #define FP21_OFFSET 21 #define FP22_OFFSET 22 #define FP23_OFFSET 23 #define FP24_OFFSET 24 #define FP25_OFFSET 25 #define FP26_OFFSET 26 #define FP27_OFFSET 27 #define FP28_OFFSET 28 #define FP29_OFFSET 29 #define FP30_OFFSET 30 #define FP31_OFFSET 31 /*PAGE * * _CPU_ISR_Get_level */#if 0unsigned32 _CPU_ISR_Get_level( void ){ /* * This routine returns the current interrupt level. */}#endif/* return the current exception level for the 4650 */FRAME(_CPU_ISR_Get_level,sp,0,ra) mfc0 v0,C0_SR nop andi v0,SR_EXL srl v0,1 j raENDFRAME(_CPU_ISR_Get_level)FRAME(_CPU_ISR_Set_level,sp,0,ra) nop mfc0 v0,C0_SR nop andi v0,SR_EXL beqz v0,_CPU_ISR_Set_1 /* normalize v0 */ nop li v0,1 _CPU_ISR_Set_1: beq v0,a0,_CPU_ISR_Set_exit /* if (current_level != new_level ) */ nop bnez a0,_CPU_ISR_Set_2 nop nop mfc0 t0,C0_SR nop li t1,~SR_EXL and t0,t1 nop mtc0 t0,C0_SR /* disable exception level */ nop j ra nop_CPU_ISR_Set_2: nop mfc0 t0,C0_SR nop li t1,~SR_IE and t0,t1 nop mtc0 t0,C0_SR /* first disable ie bit (recommended) */ nop ori t0,SR_EXL|SR_IE /* enable exception level */ nop mtc0 t0,C0_SR nop_CPU_ISR_Set_exit: j ra nopENDFRAME(_CPU_ISR_Set_level)/* * _CPU_Context_save_fp_context * * 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. * * Sometimes a macro implementation of this is in cpu.h which dereferences * the ** and a similarly named routine in this file is passed something * like a (Context_Control_fp *). The general rule on making this decision * is to avoid writing assembly language. *//* void _CPU_Context_save_fp( * void **fp_context_ptr * ) * { * } */FRAME(_CPU_Context_save_fp,sp,0,ra) .set noat ld a1,(a0) swc1 $f0,FP0_OFFSET*4(a1) swc1 $f1,FP1_OFFSET*4(a1) swc1 $f2,FP2_OFFSET*4(a1) swc1 $f3,FP3_OFFSET*4(a1) swc1 $f4,FP4_OFFSET*4(a1) swc1 $f5,FP5_OFFSET*4(a1) swc1 $f6,FP6_OFFSET*4(a1) swc1 $f7,FP7_OFFSET*4(a1) swc1 $f8,FP8_OFFSET*4(a1) swc1 $f9,FP9_OFFSET*4(a1) swc1 $f10,FP10_OFFSET*4(a1) swc1 $f11,FP11_OFFSET*4(a1) swc1 $f12,FP12_OFFSET*4(a1) swc1 $f13,FP13_OFFSET*4(a1) swc1 $f14,FP14_OFFSET*4(a1) swc1 $f15,FP15_OFFSET*4(a1) swc1 $f16,FP16_OFFSET*4(a1) swc1 $f17,FP17_OFFSET*4(a1) swc1 $f18,FP18_OFFSET*4(a1) swc1 $f19,FP19_OFFSET*4(a1) swc1 $f20,FP20_OFFSET*4(a1) swc1 $f21,FP21_OFFSET*4(a1) swc1 $f22,FP22_OFFSET*4(a1) swc1 $f23,FP23_OFFSET*4(a1) swc1 $f24,FP24_OFFSET*4(a1) swc1 $f25,FP25_OFFSET*4(a1) swc1 $f26,FP26_OFFSET*4(a1) swc1 $f27,FP27_OFFSET*4(a1) swc1 $f28,FP28_OFFSET*4(a1) swc1 $f29,FP29_OFFSET*4(a1) swc1 $f30,FP30_OFFSET*4(a1) swc1 $f31,FP31_OFFSET*4(a1) j ra nop .set atENDFRAME(_CPU_Context_save_fp)/* * _CPU_Context_restore_fp_context * * 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. * * Sometimes a macro implementation of this is in cpu.h which dereferences * the ** and a similarly named routine in this file is passed something * like a (Context_Control_fp *). The general rule on making this decision * is to avoid writing assembly language. *//* void _CPU_Context_restore_fp( * void **fp_context_ptr * ) * { * } */FRAME(_CPU_Context_restore_fp,sp,0,ra) .set noat ld a1,(a0) lwc1 $f0,FP0_OFFSET*4(a1) lwc1 $f1,FP1_OFFSET*4(a1) lwc1 $f2,FP2_OFFSET*4(a1) lwc1 $f3,FP3_OFFSET*4(a1) lwc1 $f4,FP4_OFFSET*4(a1) lwc1 $f5,FP5_OFFSET*4(a1) lwc1 $f6,FP6_OFFSET*4(a1) lwc1 $f7,FP7_OFFSET*4(a1) lwc1 $f8,FP8_OFFSET*4(a1) lwc1 $f9,FP9_OFFSET*4(a1) lwc1 $f10,FP10_OFFSET*4(a1) lwc1 $f11,FP11_OFFSET*4(a1) lwc1 $f12,FP12_OFFSET*4(a1) lwc1 $f13,FP13_OFFSET*4(a1) lwc1 $f14,FP14_OFFSET*4(a1) lwc1 $f15,FP15_OFFSET*4(a1) lwc1 $f16,FP16_OFFSET*4(a1) lwc1 $f17,FP17_OFFSET*4(a1) lwc1 $f18,FP18_OFFSET*4(a1) lwc1 $f19,FP19_OFFSET*4(a1) lwc1 $f20,FP20_OFFSET*4(a1) lwc1 $f21,FP21_OFFSET*4(a1) lwc1 $f22,FP22_OFFSET*4(a1) lwc1 $f23,FP23_OFFSET*4(a1) lwc1 $f24,FP24_OFFSET*4(a1) lwc1 $f25,FP25_OFFSET*4(a1) lwc1 $f26,FP26_OFFSET*4(a1) lwc1 $f27,FP27_OFFSET*4(a1) lwc1 $f28,FP28_OFFSET*4(a1) lwc1 $f29,FP29_OFFSET*4(a1) lwc1 $f30,FP30_OFFSET*4(a1) lwc1 $f31,FP31_OFFSET*4(a1) j ra nop .set atENDFRAME(_CPU_Context_restore_fp)/* _CPU_Context_switch * * This routine performs a normal non-FP context switch. *//* void _CPU_Context_switch( * Context_Control *run, * Context_Control *heir * ) * { * } */FRAME(_CPU_Context_switch,sp,0,ra) mfc0 t0,C0_SR li t1,~SR_IE sd t0,C0_SR_OFFSET*8(a0) /* save status register */ and t0,t1 mtc0 t0,C0_SR /* first disable ie bit (recommended) */ ori t0,SR_EXL|SR_IE /* enable exception level to disable interrupts */ mtc0 t0,C0_SR sd ra,RA_OFFSET*8(a0) /* save current context */ sd sp,SP_OFFSET*8(a0) sd fp,FP_OFFSET*8(a0) sd s0,S0_OFFSET*8(a0) sd s1,S1_OFFSET*8(a0) sd s2,S2_OFFSET*8(a0) sd s3,S3_OFFSET*8(a0) sd s4,S4_OFFSET*8(a0) sd s5,S5_OFFSET*8(a0) sd s6,S6_OFFSET*8(a0) sd s7,S7_OFFSET*8(a0) dmfc0 t0,C0_EPC sd t0,C0_EPC_OFFSET*8(a0)_CPU_Context_switch_restore: ld s0,S0_OFFSET*8(a1) /* restore context */ ld s1,S1_OFFSET*8(a1) ld s2,S2_OFFSET*8(a1) ld s3,S3_OFFSET*8(a1) ld s4,S4_OFFSET*8(a1) ld s5,S5_OFFSET*8(a1) ld s6,S6_OFFSET*8(a1) ld s7,S7_OFFSET*8(a1) ld fp,FP_OFFSET*8(a1) ld sp,SP_OFFSET*8(a1) ld ra,RA_OFFSET*8(a1) ld t0,C0_EPC_OFFSET*8(a1) dmtc0 t0,C0_EPC ld t0,C0_SR_OFFSET*8(a1) andi t0,SR_EXL bnez t0,_CPU_Context_1 /* set exception level from restore context */ li t0,~SR_EXL mfc0 t1,C0_SR nop and t1,t0 mtc0 t1,C0_SR_CPU_Context_1: j ra nopENDFRAME(_CPU_Context_switch)/* * _CPU_Context_restore * * This routine is generally used only to restart self in an * efficient manner. It may simply be a label in _CPU_Context_switch. * * NOTE: May be unnecessary to reload some registers. */#if 0void _CPU_Context_restore( Context_Control *new_context){}#endifFRAME(_CPU_Context_restore,sp,0,ra) dadd a1,a0,zero j _CPU_Context_switch_restore nopENDFRAME(_CPU_Context_restore)EXTERN(_ISR_Nest_level, SZ_INT)EXTERN(_Thread_Dispatch_disable_level,SZ_INT)EXTERN(_Context_Switch_necessary,SZ_INT)EXTERN(_ISR_Signals_to_thread_executing,SZ_INT).extern _Thread_Dispatch.extern _ISR_Vector_table/* void __ISR_Handler() * * This routine provides the RTEMS interrupt management. * */#if 0void _ISR_Handler(){ /* * This discussion ignores a lot of the ugly details in a real * implementation such as saving enough registers/state to be * able to do something real. Keep in mind that the goal is * to invoke a user's ISR handler which is written in C and * uses a certain set of registers. * * Also note that the exact order is to a large extent flexible. * Hardware will dictate a sequence for a certain subset of * _ISR_Handler while requirements for setting */ /* * At entry to "common" _ISR_Handler, the vector number must be * available. On some CPUs the hardware puts either the vector * number or the offset into the vector table for this ISR in a * known place. If the hardware does not give us this information, * then the assembly portion of RTEMS for this port will contain * a set of distinct interrupt entry points which somehow place * the vector number in a known place (which is safe if another * interrupt nests this one) and branches to _ISR_Handler. * */#endifFRAME(_ISR_Handler,sp,0,ra).set noreorder#if USE_IDTKIT/* IDT/Kit incorrectly adds 4 to EPC before returning. This compensates */ lreg k0, R_EPC*R_SZ(sp) daddiu k0,k0,-4 sreg k0, R_EPC*R_SZ(sp) lreg k0, R_CAUSE*R_SZ(sp) li k1, ~CAUSE_BD and k0, k1 sreg k0, R_CAUSE*R_SZ(sp)#endif /* save registers not already saved by IDT/sim */ stackadd sp,sp,-EXCP_STACK_SIZE /* store ra on the stack */ sreg ra, R_RA*R_SZ(sp) sreg v0, R_V0*R_SZ(sp) sreg v1, R_V1*R_SZ(sp) sreg a0, R_A0*R_SZ(sp) sreg a1, R_A1*R_SZ(sp) sreg a2, R_A2*R_SZ(sp) sreg a3, R_A3*R_SZ(sp) sreg t0, R_T0*R_SZ(sp) sreg t1, R_T1*R_SZ(sp) sreg t2, R_T2*R_SZ(sp) sreg t3, R_T3*R_SZ(sp) sreg t4, R_T4*R_SZ(sp) sreg t5, R_T5*R_SZ(sp) sreg t6, R_T6*R_SZ(sp) sreg t7, R_T7*R_SZ(sp) mflo k0 sreg t8, R_T8*R_SZ(sp) sreg k0, R_MDLO*R_SZ(sp) sreg t9, R_T9*R_SZ(sp) mfhi k0 sreg gp, R_GP*R_SZ(sp) sreg fp, R_FP*R_SZ(sp) sreg k0, R_MDHI*R_SZ(sp) .set noat sreg AT, R_AT*R_SZ(sp) .set at stackadd sp,sp,-40 /* store ra on the stack */ sd ra,32(sp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -