From f198c63d6a1d172aef422353e42b41f8cb128275 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 6 Sep 1996 18:11:41 +0000 Subject: new file for MIPS port by Craig Lebakken (lebakken@minn.net) and Derrick Ostertag (ostertag@transition.com). --- c/src/exec/score/cpu/mips/cpu_asm.S | 972 ++++++++++++++++++++++++++++++++++++ 1 file changed, 972 insertions(+) create mode 100644 c/src/exec/score/cpu/mips/cpu_asm.S (limited to 'c/src/exec/score/cpu/mips/cpu_asm.S') diff --git a/c/src/exec/score/cpu/mips/cpu_asm.S b/c/src/exec/score/cpu/mips/cpu_asm.S new file mode 100644 index 0000000000..d9e38231bf --- /dev/null +++ b/c/src/exec/score/cpu/mips/cpu_asm.S @@ -0,0 +1,972 @@ +/* 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 + * + * 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 c/src/exec/score/cpu/no_cpu/cpu_asm.s: + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * cpu_asm.c,v 1.5 1995/09/26 19:25:39 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 0 +unsigned32 _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 ra +ENDFRAME(_CPU_ISR_Get_level) + +FRAME(_CPU_ISR_Set_level,sp,0,ra) + nop + mfc0 a0,C0_SR + nop + andi a0,SR_EXL + beqz a0,_CPU_ISR_Set_1 /* normalize a0 */ + nop + li a0,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 + nop +ENDFRAME(_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 at +ENDFRAME(_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 at +ENDFRAME(_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 + nop +ENDFRAME(_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 0 +void _CPU_Context_restore( + Context_Control *new_context +) +{ +} +#endif + +FRAME(_CPU_Context_restore,sp,0,ra) + dadd a1,a0,zero + j _CPU_Context_switch_restore + nop +ENDFRAME(_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 0 +void _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. + * + */ +#endif +FRAME(_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) + +/* determine if an interrupt generated this exception */ + mfc0 k0,C0_CAUSE + and k1,k0,CAUSE_EXCMASK + bnez k1,_ISR_Handler_prom_exit /* not an external interrupt, pass exception to Monitor */ + mfc0 k1,C0_SR + and k0,k1 + and k0,CAUSE_IPMASK + beq k0,zero,_ISR_Handler_quick_exit /* external interrupt not enabled, ignore */ + nop + + /* + * save some or all context on stack + * may need to save some special interrupt information for exit + * + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * if ( _ISR_Nest_level == 0 ) + * switch to software interrupt stack + * #endif + */ +#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + lint t0,_ISR_Nest_level + beq t0, zero, _ISR_Handler_1 + nop + /* switch stacks */ +_ISR_Handler_1: +#else + lint t0,_ISR_Nest_level +#endif + /* + * _ISR_Nest_level++; + */ + addi t0,t0,1 + sint t0,_ISR_Nest_level + /* + * _Thread_Dispatch_disable_level++; + */ + lint t1,_Thread_Dispatch_disable_level + addi t1,t1,1 + sint t1,_Thread_Dispatch_disable_level +#if 0 + nop + j _ISR_Handler_4 + nop + /* + * while ( interrupts_pending(cause_reg) ) { + * vector = BITFIELD_TO_INDEX(cause_reg); + * (*_ISR_Vector_table[ vector ])( vector ); + * } + */ +_ISR_Handler_2: +/* software interrupt priorities can be applied here */ + li t1,-1 +/* convert bit field into interrupt index */ +_ISR_Handler_3: + andi t2,t0,1 + addi t1,1 + beql t2,zero,_ISR_Handler_3 + dsrl t0,1 + li t1,7 + dsll t1,3 /* convert index to byte offset (*8) */ + la t3,_ISR_Vector_table + intadd t1,t3 + lint t1,(t1) + jalr t1 + nop + j _ISR_Handler_5 + nop +_ISR_Handler_4: + mfc0 t0,C0_CAUSE + andi t0,CAUSE_IPMASK + bne t0,zero,_ISR_Handler_2 + dsrl t0,t0,8 +_ISR_Handler_5: +#else + nop + li t1,7 + dsll t1,t1,SZ_INT_POW2 + la t3,_ISR_Vector_table + intadd t1,t3 + lint t1,(t1) + jalr t1 + nop +#endif + /* + * --_ISR_Nest_level; + */ + lint t2,_ISR_Nest_level + addi t2,t2,-1 + sint t2,_ISR_Nest_level + /* + * --_Thread_Dispatch_disable_level; + */ + lint t1,_Thread_Dispatch_disable_level + addi t1,t1,-1 + sint t1,_Thread_Dispatch_disable_level + /* + * if ( _Thread_Dispatch_disable_level || _ISR_Nest_level ) + * goto the label "exit interrupt (simple case)" + */ + or t0,t2,t1 + bne t0,zero,_ISR_Handler_exit + nop + /* + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * restore stack + * #endif + * + * if ( !_Context_Switch_necessary && !_ISR_Signals_to_thread_executing ) + * goto the label "exit interrupt (simple case)" + */ + lint t0,_Context_Switch_necessary + lint t1,_ISR_Signals_to_thread_executing + or t0,t0,t1 + beq t0,zero,_ISR_Handler_exit + nop + + /* + * call _Thread_Dispatch() or prepare to return to _ISR_Dispatch + */ + jal _Thread_Dispatch + nop + /* + * prepare to get out of interrupt + * return from interrupt (maybe to _ISR_Dispatch) + * + * LABEL "exit interrupt (simple case): + * prepare to get out of interrupt + * return from interrupt + */ +_ISR_Handler_exit: + ld ra,32(sp) + stackadd sp,sp,40 + +/* restore interrupt context from stack */ + lreg k0, R_MDLO*R_SZ(sp) + mtlo k0 + lreg k0, R_MDHI*R_SZ(sp) + lreg a2, R_A2*R_SZ(sp) + mthi k0 + lreg a3, R_A3*R_SZ(sp) + lreg t0, R_T0*R_SZ(sp) + lreg t1, R_T1*R_SZ(sp) + lreg t2, R_T2*R_SZ(sp) + lreg t3, R_T3*R_SZ(sp) + lreg t4, R_T4*R_SZ(sp) + lreg t5, R_T5*R_SZ(sp) + lreg t6, R_T6*R_SZ(sp) + lreg t7, R_T7*R_SZ(sp) + lreg t8, R_T8*R_SZ(sp) + lreg t9, R_T9*R_SZ(sp) + lreg gp, R_GP*R_SZ(sp) + lreg fp, R_FP*R_SZ(sp) + lreg ra, R_RA*R_SZ(sp) + lreg a0, R_A0*R_SZ(sp) + lreg a1, R_A1*R_SZ(sp) + lreg v1, R_V1*R_SZ(sp) + lreg v0, R_V0*R_SZ(sp) + .set noat + lreg AT, R_AT*R_SZ(sp) + .set at + + stackadd sp,sp,EXCP_STACK_SIZE /* store ra on the stack */ + +#if USE_IDTKIT +/* we handled exception, so return non-zero value */ + li v0,1 +#endif + +_ISR_Handler_quick_exit: +#ifdef USE_IDTKIT + j ra +#else + eret +#endif + nop + +_ISR_Handler_prom_exit: +#ifdef CPU_R3000 + la k0, (R_VEC+((48)*8)) +#endif + +#ifdef CPU_R4000 + la k0, (R_VEC+((112)*8)) /* R4000 Sim's location is different */ +#endif + j k0 + nop + + .set reorder + +ENDFRAME(_ISR_Handler) + + +FRAME(mips_enable_interrupts,sp,0,ra) + mfc0 t0,C0_SR /* get status reg */ + nop + or t0,t0,a0 + mtc0 t0,C0_SR /* save updated status reg */ + j ra + nop +ENDFRAME(mips_enable_interrupts) + +FRAME(mips_disable_interrupts,sp,0,ra) + mfc0 v0,C0_SR /* get status reg */ + li t1,SR_IMASK /* t1 = load interrupt mask word */ + not t0,t1 /* t0 = ~t1 */ + and t0,v0 /* clear imask bits */ + mtc0 t0,C0_SR /* save status reg */ + and v0,t1 /* mask return value (only return imask bits) */ + jr ra + nop +ENDFRAME(mips_disable_interrupts) + +FRAME(mips_enable_global_interrupts,sp,0,ra) + mfc0 t0,C0_SR /* get status reg */ + nop + ori t0,SR_IE + mtc0 t0,C0_SR /* save updated status reg */ + j ra + nop +ENDFRAME(mips_enable_global_interrupts) + +FRAME(mips_disable_global_interrupts,sp,0,ra) + li t1,SR_IE + mfc0 t0,C0_SR /* get status reg */ + not t1 + and t0,t1 + mtc0 t0,C0_SR /* save updated status reg */ + j ra + nop +ENDFRAME(mips_disable_global_interrupts) + +/* return the value of the status register in v0. Used for debugging */ +FRAME(mips_get_sr,sp,0,ra) + mfc0 v0,C0_SR + j ra + nop +ENDFRAME(mips_get_sr) + +FRAME(mips_break,sp,0,ra) +#if 1 + break 0x0 + j mips_break +#else + j ra +#endif + nop +ENDFRAME(mips_break) + +/*PAGE + * + * _CPU_Internal_threads_Idle_thread_body + * + * NOTES: + * + * 1. This is the same as the regular CPU independent algorithm. + * + * 2. If you implement this using a "halt", "idle", or "shutdown" + * instruction, then don't forget to put it in an infinite loop. + * + * 3. Be warned. Some processors with onboard DMA have been known + * to stop the DMA if the CPU were put in IDLE mode. This might + * also be a problem with other on-chip peripherals. So use this + * hook with caution. + */ + +FRAME(_CPU_Thread_Idle_body,sp,0,ra) + wait /* enter low power mode */ + j _CPU_Thread_Idle_body + nop +ENDFRAME(_CPU_Thread_Idle_body) + +#define VEC_CODE_LENGTH 10*4 + +/************************************************************************** +** +** init_exc_vecs() - moves the exception code into the addresses +** reserved for exception vectors +** +** UTLB Miss exception vector at address 0x80000000 +** +** General exception vector at address 0x80000080 +** +** RESET exception vector is at address 0xbfc00000 +** +***************************************************************************/ + +#define INITEXCFRM ((2*4)+4) /* ra + 2 arguments */ +FRAME(init_exc_vecs,sp,0,ra) +/* This code yanked from SIM */ +#if defined(CPU_R3000) + .set noreorder + la t1,exc_utlb_code + la t2,exc_norm_code + li t3,UT_VEC + li t4,E_VEC + li t5,VEC_CODE_LENGTH +1: + lw t6,0(t1) + lw t7,0(t2) + sw t6,0(t3) + sw t7,0(t4) + addiu t1,4 + addiu t3,4 + addiu t4,4 + subu t5,4 + bne t5,zero,1b + addiu t2,4 + move t5,ra # assumes clear_cache doesnt use t5 + li a0,UT_VEC + jal clear_cache + li a1,VEC_CODE_LENGTH + nop + li a0,E_VEC + jal clear_cache + li a1,VEC_CODE_LENGTH + move ra,t5 # restore ra + j ra + nop + .set reorder +#endif +#if defined(CPU_R4000) + .set reorder + move t5,ra # assumes clear_cache doesnt use t5 + + /* TLB exception vector */ + la t1,exc_tlb_code + li t2,T_VEC |K1BASE + li t3,VEC_CODE_LENGTH +1: + lw t6,0(t1) + addiu t1,4 + subu t3,4 + sw t6,0(t2) + addiu t2,4 + bne t3,zero,1b + + li a0,T_VEC + li a1,VEC_CODE_LENGTH + jal clear_cache + + la t1,exc_xtlb_code + li t2,X_VEC |K1BASE + li t3,VEC_CODE_LENGTH +1: + lw t6,0(t1) + addiu t1,4 + subu t3,4 + sw t6,0(t2) + addiu t2,4 + bne t3,zero,1b + + /* extended TLB exception vector */ + li a0,X_VEC + li a1,VEC_CODE_LENGTH + jal clear_cache + + /* cache error exception vector */ + la t1,exc_cache_code + li t2,C_VEC |K1BASE + li t3,VEC_CODE_LENGTH +1: + lw t6,0(t1) + addiu t1,4 + subu t3,4 + sw t6,0(t2) + addiu t2,4 + bne t3,zero,1b + + li a0,C_VEC + li a1,VEC_CODE_LENGTH + jal clear_cache + + /* normal exception vector */ + la t1,exc_norm_code + li t2,E_VEC |K1BASE + li t3,VEC_CODE_LENGTH +1: + lw t6,0(t1) + addiu t1,4 + subu t3,4 + sw t6,0(t2) + addiu t2,4 + bne t3,zero,1b + + li a0,E_VEC + li a1,VEC_CODE_LENGTH + jal clear_cache + + move ra,t5 # restore ra + j ra +#endif +ENDFRAME(init_exc_vecs) + + +#if defined(CPU_R4000) +FRAME(exc_tlb_code,sp,0,ra) +#ifdef CPU_R3000 + la k0, (R_VEC+((48)*8)) +#endif + +#ifdef CPU_R4000 + la k0, (R_VEC+((112)*8)) /* R4000 Sim's location is different */ +#endif + j k0 + nop + +ENDFRAME(exc_tlb_code) + + +FRAME(exc_xtlb_code,sp,0,ra) +#ifdef CPU_R3000 + la k0, (R_VEC+((48)*8)) +#endif + +#ifdef CPU_R4000 + la k0, (R_VEC+((112)*8)) /* R4000 Sim's location is different */ +#endif + j k0 + nop + +ENDFRAME(exc_xtlb_code) + + +FRAME(exc_cache_code,sp,0,ra) +#ifdef CPU_R3000 + la k0, (R_VEC+((48)*8)) +#endif + +#ifdef CPU_R4000 + la k0, (R_VEC+((112)*8)) /* R4000 Sim's location is different */ +#endif + j k0 + nop + +ENDFRAME(exc_cache_code) + + +FRAME(exc_norm_code,sp,0,ra) + la k0, _ISR_Handler /* generic external int hndlr */ + j k0 + nop + subu sp, EXCP_STACK_SIZE /* set up local stack frame */ +ENDFRAME(exc_norm_code) +#endif + +/************************************************************************** +** +** enable_int(mask) - enables interrupts - mask is positioned so it only +** needs to be or'ed into the status reg. This +** also does some other things !!!! caution should +** be used if invoking this while in the middle +** of a debugging session where the client may have +** nested interrupts. +** +****************************************************************************/ +FRAME(enable_int,sp,0,ra) + .set noreorder + mfc0 t0,C0_SR + or a0,1 + or t0,a0 + mtc0 t0,C0_SR + j ra + nop + .set reorder +ENDFRAME(enable_int) + + +/*************************************************************************** +** +** disable_int(mask) - disable the interrupt - mask is the complement +** of the bits to be cleared - i.e. to clear ext int +** 5 the mask would be - 0xffff7fff +** +****************************************************************************/ +FRAME(disable_int,sp,0,ra) + .set noreorder + mfc0 t0,C0_SR + nop + and t0,a0 + mtc0 t0,C0_SR + j ra + nop +ENDFRAME(disable_int) + + -- cgit v1.2.3