URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [exec/] [score/] [cpu/] [mips64orion/] [cpu_asm.S] - Rev 1765
Compare with Previous | Blame | View Log
/* 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 c/src/exec/score/cpu/no_cpu/cpu_asm.s:
*
* 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.OARcorp.com/rtems/license.html.
*
* $Id: cpu_asm.S,v 1.2 2001-09-27 11:59:28 chris 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 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
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)