* cpu.c: Enhancements and fixes for modifying the SR when changing
	the interrupt level.
	* cpu_asm.S: Fixed handling of FP enable bit so it is properly
	managed on a per-task basis, improved handling of interrupt levels,
	and made deferred FP contexts work on the MIPS.
	* rtems/score/cpu.h: Modified to support above changes.
This commit is contained in:
Joel Sherrill
2002-02-01 15:00:30 +00:00
parent 6d41a8747c
commit e6dec71c27
8 changed files with 496 additions and 304 deletions

View File

@@ -1,3 +1,12 @@
2001-02-01 Greg Menke <gregory.menke@gsfc.nasa.gov>
* cpu.c: Enhancements and fixes for modifying the SR when changing
the interrupt level.
* cpu_asm.S: Fixed handling of FP enable bit so it is properly
managed on a per-task basis, improved handling of interrupt levels,
and made deferred FP contexts work on the MIPS.
* rtems/score/cpu.h: Modified to support above changes.
2002-01-28 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* rtems/Makefile.am: Removed.

View File

@@ -82,51 +82,66 @@ unsigned32 _CPU_ISR_Get_level( void )
mips_get_sr(sr);
#if __mips == 3
return ((sr & SR_EXL) >> 1);
/* EXL bit and shift down hardware ints into bits 1 thru 6 */
return ((sr & SR_EXL) >> 1) + ((sr & 0xfc00) >> 9);
#elif __mips == 1
return ((sr & SR_IEC) ? 0 : 1);
/* IEC bit and shift down hardware ints into bits 1 thru 6 */
return (sr & SR_IEC) + ((sr & 0xfc00) >> 9);
#else
#error "CPU ISR level: unknown MIPS level for SR handling"
#endif
}
void _CPU_ISR_Set_level( unsigned32 new_level )
{
unsigned int sr;
unsigned int sr, srbits;
/*
** mask off the int level bits only so we can
** preserve software int settings and FP enable
** for this thread. Note we don't force software ints
** enabled when changing level, they were turned on
** when this task was created, but may have been turned
** off since, so we'll just leave them alone.
*/
mips_get_sr(sr);
#if __mips == 3
mips_set_sr(sr & ~SR_IE); /* first disable ie bit (recommended) */
srbits = sr & ~(0xfc00 | SR_EXL | SR_IE);
sr = srbits | ((new_level==0)? (0xfc00 | SR_EXL | SR_IE): \
(((new_level<<9) & 0xfc000) | \
(new_level & 1)?(SR_EXL | SR_IE):0));
/*
if ( (new_level & SR_EXL) == (sr & SR_EXL) )
return;
if ( (new_level & SR_EXL) == 0 ) {
sr &= ~SR_EXL; /* clear the EXL bit */
sr &= ~SR_EXL; * clear the EXL bit *
mips_set_sr(sr);
} else {
sr &= ~SR_IE;
mips_set_sr(sr); /* first disable ie bit (recommended) */
sr |= SR_EXL|SR_IE; /* enable exception level */
mips_set_sr(sr); /* first disable ie bit (recommended) */
sr |= SR_EXL|SR_IE; * enable exception level *
mips_set_sr(sr); * first disable ie bit (recommended) *
}
*/
#elif __mips == 1
if ( (new_level & SR_IEC) == (sr & SR_IEC) )
return;
sr &= ~SR_IEC; /* clear the IEC bit */
if ( !new_level )
sr |= SR_IEC; /* enable interrupts */
mips_set_sr(sr);
mips_set_sr( (sr & ~SR_IEC) );
srbits = sr & ~(0xfc00 | SR_IEC);
sr = srbits | ((new_level==0)?0xfc01:( ((new_level<<9) & 0xfc000) | (new_level & 1)));
#else
#error "CPU ISR level: unknown MIPS level for SR handling"
#endif
mips_set_sr( sr );
}
/*PAGE
@@ -153,7 +168,7 @@ void _CPU_ISR_install_raw_handler(
* table used by the CPU to dispatch interrupt handlers.
*
* Because all interrupts are vectored through the same exception handler
* this is not necessary on this port.
* this is not necessary on thi sport.
*/
}

View File

@@ -23,6 +23,13 @@
* 2001: Joel Sherrill <joel@OARcorp.com> continued this rework,
* rewriting as much as possible in C and added the JMR3904 BSP
* so testing could be performed on a simulator.
* 2001: Greg Menke <gregory.menke@gsfc.nasa.gov>, bench tested ISR
* performance, tweaking this code and the isr vectoring routines
* to reduce overhead & latencies. Added optional
* instrumentation as well.
* 2002: Greg Menke <gregory.menke@gsfc.nasa.gov>, overhauled cpu_asm.S,
* cpu.c and cpu.h to manage FP vs int only tasks, interrupt levels
* and deferred FP contexts.
*
* COPYRIGHT (c) 1989-2000.
* On-Line Applications Research Corporation (OAR).
@@ -42,8 +49,9 @@
* Mongoose-ism debug tool- but may be handy in the future so we
* left it in...
*/
/* #define INSTRUMENT */
#define INSTRUMENT_ISR_VECTORING
//#define INSTRUMENT_EXECUTING_THREAD
@@ -165,10 +173,28 @@
* );
*/
#if ( CPU_HARDWARE_FP == TRUE )
#if ( CPU_HARDWARE_FP == FALSE )
FRAME(_CPU_Context_save_fp,sp,0,ra)
.set noat
ld a1,(a0)
#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
/*
** Make sure the FPU is on before we save state. This code is here
** because the FPU context switch might occur when an integer
** task is switching out w/ an FP task switching in, but the current
** FPU state was left by a sometime previously scheduled FP task.
**
** In non-deferred FP context switch, if the exiting task is FP, then
** the FPU is already on so we don't need to do this.
*/
MFC0 t0,C0_SR
li k0,SR_CU1
or t0,k0
MTC0 t0,C0_SR
#endif
ld a1,(a0)
NOP
swc1 $f0,FP0_OFFSET*F_SZ(a1)
swc1 $f1,FP1_OFFSET*F_SZ(a1)
@@ -226,10 +252,22 @@ ENDFRAME(_CPU_Context_save_fp)
* )
*/
#if ( CPU_HARDWARE_FP == TRUE )
#if ( CPU_HARDWARE_FP == FALSE )
FRAME(_CPU_Context_restore_fp,sp,0,ra)
.set noat
ld a1,(a0)
/*
** Make sure the FPU is on before we retrieve state. This code
** is here because the FPU context switch might occur when an
** integer task is switching out with a FP task switching in.
*/
MFC0 t0,C0_SR
li k0,SR_CU1
or t0,k0
MTC0 t0,C0_SR
ld a1,(a0)
NOP
lwc1 $f0,FP0_OFFSET*4(a1)
lwc1 $f1,FP1_OFFSET*4(a1)
@@ -284,13 +322,12 @@ FRAME(_CPU_Context_switch,sp,0,ra)
MFC0 t0,C0_SR
li t1,~(SR_INTERRUPT_ENABLE_BITS)
STREG t0,C0_SR_OFFSET*4(a0) /* save status register */
STREG t0,C0_SR_OFFSET*R_SZ(a0)
and t0,t1
MTC0 t0,C0_SR /* first disable ie bit (recommended) */
#if __mips == 3
ori t0,SR_EXL|SR_IE /* enable exception level to disable interrupts */
MTC0 t0,C0_SR
ori t0,(SR_EXL|SR_IE) /* enable exception level to disable interrupts */
#endif
MTC0 t0,C0_SR
STREG ra,RA_OFFSET*R_SZ(a0) /* save current context */
STREG sp,SP_OFFSET*R_SZ(a0)
@@ -304,7 +341,7 @@ FRAME(_CPU_Context_switch,sp,0,ra)
STREG s6,S6_OFFSET*R_SZ(a0)
STREG s7,S7_OFFSET*R_SZ(a0)
/*
/* EPC is readonly...
MFC0 t0,C0_EPC
NOP
STREG t0,C0_EPC_OFFSET*R_SZ(a0)
@@ -323,35 +360,64 @@ _CPU_Context_switch_restore:
LDREG s6,S6_OFFSET*R_SZ(a1)
LDREG s7,S7_OFFSET*R_SZ(a1)
/*
/* EPC is readonly...
LDREG t0,C0_EPC_OFFSET*R_SZ(a1)
NOP
MTC0 t0,C0_EPC
*/
LDREG t0, C0_SR_OFFSET*R_SZ(a1)
// NOP
//#if __mips == 3
// 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
//
//#elif __mips == 1
//
// andi t0,(SR_INTERRUPT_ENABLE_BITS) /* we know 0 disabled */
// beq t0,$0,_CPU_Context_1 /* set level from restore context */
// MFC0 t0,C0_SR
// NOP
// or t0,(SR_INTERRUPT_ENABLE_BITS) /* new_sr = old sr with enabled */
// MTC0 t0,C0_SR /* set with enabled */
// NOP
/*
** Incorporate the new thread's FP coprocessor state and interrupt mask/enable
** into the status register. We jump thru the requisite hoops to ensure we
** maintain all other SR bits as global values.
**
** Get the thread's FPU enable, int mask & int enable bits. Although we keep the
** software int enables on a per-task basis, the rtems_task_create
** Interrupt Level & int level manipulation functions cannot enable/disable them,
** so they are automatically enabled for all tasks. To turn them off, a thread
** must itself manipulate the SR register.
*/
#if __mips == 3
li k0,(SR_CU1 | SR_IMASK | SR_EXL | SR_IE)
#elif __mips == 1
li k0,(SR_CU1 | SR_IMASK | SR_IEC)
#endif
and t0,k0
MFC0 t1,C0_SR /* grab the current SR */
not k0 /* invert k0 so we can clear out the SR bits */
and t1,k0
or t0,t1 /* setup the new task's SR value */
MTC0 t0,C0_SR /* and load the new SR */
NOP
#if __mips == 3
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
#elif __mips == 1
andi t0,(SR_INTERRUPT_ENABLE_BITS) /* we know 0 disabled */
beq t0,$0,_CPU_Context_1 /* set level from restore context */
MFC0 t0,C0_SR
NOP
or t0,(SR_INTERRUPT_ENABLE_BITS) /* new_sr = old sr with enabled */
MTC0 t0,C0_SR /* set with enabled */
#endif
_CPU_Context_1:
/* _CPU_Context_1: */
j ra
NOP
ENDFRAME(_CPU_Context_switch)
@@ -450,42 +516,15 @@ FRAME(_ISR_Handler,sp,0,ra)
MFC0 t1,C0_EPC
STREG t0,R_SR*R_SZ(sp)
STREG t1,R_EPC*R_SZ(sp)
#ifdef INSTRUMENT
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t2, _Thread_Executing
nop
sw t2, 0x8001FFF0
sw t0, 0x8001F050
sw t1, 0x8001F054
li t0, 0xdeadbeef
li t1, 0xdeadbeef
li t2, 0xdeadbeef
sw ra, 0x8001F000
sw v0, 0x8001F004
sw v1, 0x8001F008
sw a0, 0x8001F00c
sw a1, 0x8001F010
sw a2, 0x8001F014
sw a3, 0x8001F018
sw t0, 0x8001F01c
sw t1, 0x8001F020
sw t2, 0x8001F024
sw t3, 0x8001F028
sw t4, 0x8001F02c
sw t5, 0x8001F030
sw t6, 0x8001F034
sw t7, 0x8001F038
sw t8, 0x8001F03c
sw t9, 0x8001F040
sw gp, 0x8001F044
sw fp, 0x8001F048
#endif
/* determine if an interrupt generated this exception */
/* determine if an interrupt generated this exception */
MFC0 k0,C0_CAUSE
NOP
@@ -515,9 +554,11 @@ _ISR_Handler_1:
/* Then where did it come from??? */
beq k0,zero,_ISR_Handler_exit
li t2,1 /* set a flag so we process interrupts */
/*
* save some or all context on stack
* may need to save some special interrupt information for exit
@@ -547,10 +588,23 @@ _ISR_Handler_1:
* Call the CPU model or BSP specific routine to decode the
* interrupt source and actually vector to device ISR handlers.
*/
#ifdef INSTRUMENT_ISR_VECTORING
nop
li t1, 1
sw t1, 0x8001e000
#endif
move a0,sp
jal mips_vector_isr_handlers
nop
#ifdef INSTRUMENT_ISR_VECTORING
li t1, 0
sw t1, 0x8001e000
nop
#endif
/*
* --_ISR_Nest_level;
*/
@@ -572,6 +626,14 @@ _ISR_Handler_1:
or t0,t2,t1
bne t0,zero,_ISR_Handler_exit
nop
/*
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
* restore stack
@@ -589,32 +651,35 @@ _ISR_Handler_1:
#ifdef INSTRUMENT
li t0,0x11111111
sw t0,0x8001F104
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0,0x8001FFF4
#endif
/* restore interrupt state from the saved status register,
* if the isr vectoring didn't so we allow nested interrupts to
* occur */
LDREG t0,R_SR*R_SZ(sp)
/*
** Turn on interrupts before entering Thread_Dispatch which
** will run for a while, thus allowing new interrupts to
** be serviced. Observe the Thread_Dispatch_disable_level interlock
** that prevents recursive entry into Thread_Dispatch.
*/
MFC0 t0, C0_SR
NOP
MTC0 t0,C0_SR
rfe
or t0, SR_INTERRUPT_ENABLE_BITS
MTC0 t0, C0_SR
NOP
jal _Thread_Dispatch
NOP
jal _Thread_Dispatch
nop
#ifdef INSTRUMENT
li t0,0x22222222
sw t0,0x8001F100
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0,0x8001FFF8
#endif
/*
* prepare to get out of interrupt
* return from interrupt (maybe to _ISR_Dispatch)
@@ -625,16 +690,19 @@ _ISR_Handler_1:
*/
_ISR_Handler_exit:
LDREG t0, R_SR*R_SZ(sp)
NOP
MTC0 t0, C0_SR
/*
** Skip the SR restore because its a global register. _CPU_Context_switch_restore
** adjusts it according to each task's configuration. If we didn't dispatch, the
** SR value isn't changing, so all we need to do is return.
**
*/
/* restore context from stack */
#ifdef INSTRUMENT
/* restore context from stack */
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0, 0x8001FFF4
sw t0, 0x8001FFFC
#endif
LDREG k0, R_MDLO*R_SZ(sp)
@@ -660,33 +728,11 @@ _ISR_Handler_exit:
LDREG a3, R_A3*R_SZ(sp)
LDREG v1, R_V1*R_SZ(sp)
LDREG v0, R_V0*R_SZ(sp)
#ifdef INSTRUMENT
sw ra, 0x8001F000
sw v0, 0x8001F004
sw v1, 0x8001F008
sw a0, 0x8001F00c
sw a1, 0x8001F010
sw a2, 0x8001F014
sw a3, 0x8001F018
sw t0, 0x8001F01c
sw t1, 0x8001F020
sw t2, 0x8001F024
sw t3, 0x8001F028
sw t4, 0x8001F02c
sw t5, 0x8001F030
sw t6, 0x8001F034
sw t7, 0x8001F038
sw t8, 0x8001F03c
sw t9, 0x8001F040
sw gp, 0x8001F044
sw fp, 0x8001F048
#endif
LDREG k0, R_EPC*R_SZ(sp)
.set noat
LDREG AT, R_AT*R_SZ(sp)
LDREG AT, R_AT*R_SZ(sp)
.set at
ADDIU sp,sp,EXCP_STACK_SIZE
@@ -697,6 +743,7 @@ _ISR_Handler_exit:
.set reorder
ENDFRAME(_ISR_Handler)
FRAME(mips_break,sp,0,ra)
#if 1
break 0x0

View File

@@ -67,7 +67,7 @@ extern "C" {
* one subroutine call is avoided entirely.]
*/
#define CPU_INLINE_ENABLE_DISPATCH TRUE
#define CPU_INLINE_ENABLE_DISPATCH FALSE
/*
* Should the body of the search loops in _Thread_queue_Enqueue_priority
@@ -207,7 +207,7 @@ extern "C" {
* must be saved as part of the preemption.
*/
#define CPU_IDLE_TASK_IS_FP FALSE
#define CPU_IDLE_TASK_IS_FP TRUE
/*
* Should the saving of the floating point registers be deferred
@@ -554,13 +554,6 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (mips_interrupt_number_of_vectors)
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
/*
* This is defined if the port has a special way to report the ISR nesting
* level. Most ports maintain the variable _ISR_Nest_level.
*/
#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
/*
* Should be large enough to run all RTEMS tests. This insures
* that a "reasonable" small application should not have any problems.
@@ -632,7 +625,8 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define _CPU_ISR_Disable( _level ) \
do { \
mips_get_sr( _level ); \
mips_set_sr( (_level) & ~SR_INTERRUPT_ENABLE_BITS ); \
mips_set_sr( _level & ~SR_INTERRUPT_ENABLE_BITS ); \
_level &= SR_INTERRUPT_ENABLE_BITS; \
} while(0)
/*
@@ -643,21 +637,22 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define _CPU_ISR_Enable( _level ) \
do { \
mips_set_sr(_level); \
unsigned int _scratch; \
mips_get_sr( _scratch ); \
mips_set_sr( (_scratch & ~SR_INTERRUPT_ENABLE_BITS) | (_level & SR_INTERRUPT_ENABLE_BITS) ); \
} while(0)
/*
* This temporarily restores the interrupt to _level before immediately
* disabling them again. This is used to divide long RTEMS critical
* sections into two or more parts. The parameter _level is not
* modified.
* modified.
*/
#define _CPU_ISR_Flash( _xlevel ) \
do { \
unsigned int _scratch; \
_CPU_ISR_Enable( _xlevel ); \
_CPU_ISR_Disable( _scratch ); \
_CPU_ISR_Disable( _xlevel ); \
} while(0)
/*
@@ -701,22 +696,52 @@ void _CPU_ISR_Set_level( unsigned32 ); /* in cpu.c */
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
*
* The per-thread status register holds the interrupt enable, FP enable
* and global interrupt enable for that thread. It means each thread can
* enable its own set of interrupts. If interrupts are disabled, RTEMS
* can still dispatch via blocking calls. This is the function of the
* "Interrupt Level", and on the MIPS, it controls the IEC bit and all
* the hardware interrupts as defined in the SR. Software ints
* are automatically enabled for all threads, as they will only occur under
* program control anyhow. Besides, the interrupt level parm is only 8 bits,
* and controlling the software ints plus the others would require 9.
*
* If the Interrupt Level is 0, all ints are on. Otherwise, the
* Interrupt Level should supply a bit pattern to impose on the SR
* interrupt bits; bit 0 applies to the mips1 IEC bit/mips3 EXL&IE, bits 1 thru 6
* apply to the SR register Intr bits from bit 10 thru bit 15. Bit 7 of
* the Interrupt Level parameter is unused at this time.
*
* These are the only per-thread SR bits, the others are maintained
* globally & explicitly preserved by the Context Switch code in cpu_asm.s
*/
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
#if __mips == 3
#define _INTON (SR_EXL | SR_IE)
#endif
#if __mips == 1
#define _INTON SR_IEC
#endif
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, _isr, _entry_point, _is_fp ) \
{ \
unsigned32 _stack_tmp = \
(unsigned32)(_stack_base) + (_size) - CPU_STACK_ALIGNMENT; \
unsigned32 _intlvl = _isr & 0xff; \
_stack_tmp &= ~(CPU_STACK_ALIGNMENT - 1); \
(_the_context)->sp = _stack_tmp; \
(_the_context)->fp = _stack_tmp; \
(_the_context)->ra = (unsigned64)_entry_point; \
(_the_context)->c0_sr = ((_the_context)->c0_sr & 0x0fff0000) | \
((_isr)?0xff00:0xff01) | \
((_is_fp)?0x20000000:0x10000000); \
(_the_context)->c0_sr = ((_intlvl==0)?(0xFF00 | _INTON):( ((_intlvl<<9) & 0xfc00) | \
0x300 | \
((_intlvl & 1)?_INTON:0)) ) | \
SR_CU0 | ((_is_fp)?SR_CU1:0); \
}
/*
* This routine is responsible for somehow restarting the currently
* executing task. If you are lucky, then all that is necessary

View File

@@ -1,3 +1,12 @@
2001-02-01 Greg Menke <gregory.menke@gsfc.nasa.gov>
* cpu.c: Enhancements and fixes for modifying the SR when changing
the interrupt level.
* cpu_asm.S: Fixed handling of FP enable bit so it is properly
managed on a per-task basis, improved handling of interrupt levels,
and made deferred FP contexts work on the MIPS.
* rtems/score/cpu.h: Modified to support above changes.
2002-01-28 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* rtems/Makefile.am: Removed.

View File

@@ -82,51 +82,66 @@ unsigned32 _CPU_ISR_Get_level( void )
mips_get_sr(sr);
#if __mips == 3
return ((sr & SR_EXL) >> 1);
/* EXL bit and shift down hardware ints into bits 1 thru 6 */
return ((sr & SR_EXL) >> 1) + ((sr & 0xfc00) >> 9);
#elif __mips == 1
return ((sr & SR_IEC) ? 0 : 1);
/* IEC bit and shift down hardware ints into bits 1 thru 6 */
return (sr & SR_IEC) + ((sr & 0xfc00) >> 9);
#else
#error "CPU ISR level: unknown MIPS level for SR handling"
#endif
}
void _CPU_ISR_Set_level( unsigned32 new_level )
{
unsigned int sr;
unsigned int sr, srbits;
/*
** mask off the int level bits only so we can
** preserve software int settings and FP enable
** for this thread. Note we don't force software ints
** enabled when changing level, they were turned on
** when this task was created, but may have been turned
** off since, so we'll just leave them alone.
*/
mips_get_sr(sr);
#if __mips == 3
mips_set_sr(sr & ~SR_IE); /* first disable ie bit (recommended) */
srbits = sr & ~(0xfc00 | SR_EXL | SR_IE);
sr = srbits | ((new_level==0)? (0xfc00 | SR_EXL | SR_IE): \
(((new_level<<9) & 0xfc000) | \
(new_level & 1)?(SR_EXL | SR_IE):0));
/*
if ( (new_level & SR_EXL) == (sr & SR_EXL) )
return;
if ( (new_level & SR_EXL) == 0 ) {
sr &= ~SR_EXL; /* clear the EXL bit */
sr &= ~SR_EXL; * clear the EXL bit *
mips_set_sr(sr);
} else {
sr &= ~SR_IE;
mips_set_sr(sr); /* first disable ie bit (recommended) */
sr |= SR_EXL|SR_IE; /* enable exception level */
mips_set_sr(sr); /* first disable ie bit (recommended) */
sr |= SR_EXL|SR_IE; * enable exception level *
mips_set_sr(sr); * first disable ie bit (recommended) *
}
*/
#elif __mips == 1
if ( (new_level & SR_IEC) == (sr & SR_IEC) )
return;
sr &= ~SR_IEC; /* clear the IEC bit */
if ( !new_level )
sr |= SR_IEC; /* enable interrupts */
mips_set_sr(sr);
mips_set_sr( (sr & ~SR_IEC) );
srbits = sr & ~(0xfc00 | SR_IEC);
sr = srbits | ((new_level==0)?0xfc01:( ((new_level<<9) & 0xfc000) | (new_level & 1)));
#else
#error "CPU ISR level: unknown MIPS level for SR handling"
#endif
mips_set_sr( sr );
}
/*PAGE
@@ -153,7 +168,7 @@ void _CPU_ISR_install_raw_handler(
* table used by the CPU to dispatch interrupt handlers.
*
* Because all interrupts are vectored through the same exception handler
* this is not necessary on this port.
* this is not necessary on thi sport.
*/
}

View File

@@ -23,6 +23,13 @@
* 2001: Joel Sherrill <joel@OARcorp.com> continued this rework,
* rewriting as much as possible in C and added the JMR3904 BSP
* so testing could be performed on a simulator.
* 2001: Greg Menke <gregory.menke@gsfc.nasa.gov>, bench tested ISR
* performance, tweaking this code and the isr vectoring routines
* to reduce overhead & latencies. Added optional
* instrumentation as well.
* 2002: Greg Menke <gregory.menke@gsfc.nasa.gov>, overhauled cpu_asm.S,
* cpu.c and cpu.h to manage FP vs int only tasks, interrupt levels
* and deferred FP contexts.
*
* COPYRIGHT (c) 1989-2000.
* On-Line Applications Research Corporation (OAR).
@@ -42,8 +49,9 @@
* Mongoose-ism debug tool- but may be handy in the future so we
* left it in...
*/
/* #define INSTRUMENT */
#define INSTRUMENT_ISR_VECTORING
//#define INSTRUMENT_EXECUTING_THREAD
@@ -165,10 +173,28 @@
* );
*/
#if ( CPU_HARDWARE_FP == TRUE )
#if ( CPU_HARDWARE_FP == FALSE )
FRAME(_CPU_Context_save_fp,sp,0,ra)
.set noat
ld a1,(a0)
#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
/*
** Make sure the FPU is on before we save state. This code is here
** because the FPU context switch might occur when an integer
** task is switching out w/ an FP task switching in, but the current
** FPU state was left by a sometime previously scheduled FP task.
**
** In non-deferred FP context switch, if the exiting task is FP, then
** the FPU is already on so we don't need to do this.
*/
MFC0 t0,C0_SR
li k0,SR_CU1
or t0,k0
MTC0 t0,C0_SR
#endif
ld a1,(a0)
NOP
swc1 $f0,FP0_OFFSET*F_SZ(a1)
swc1 $f1,FP1_OFFSET*F_SZ(a1)
@@ -226,10 +252,22 @@ ENDFRAME(_CPU_Context_save_fp)
* )
*/
#if ( CPU_HARDWARE_FP == TRUE )
#if ( CPU_HARDWARE_FP == FALSE )
FRAME(_CPU_Context_restore_fp,sp,0,ra)
.set noat
ld a1,(a0)
/*
** Make sure the FPU is on before we retrieve state. This code
** is here because the FPU context switch might occur when an
** integer task is switching out with a FP task switching in.
*/
MFC0 t0,C0_SR
li k0,SR_CU1
or t0,k0
MTC0 t0,C0_SR
ld a1,(a0)
NOP
lwc1 $f0,FP0_OFFSET*4(a1)
lwc1 $f1,FP1_OFFSET*4(a1)
@@ -284,13 +322,12 @@ FRAME(_CPU_Context_switch,sp,0,ra)
MFC0 t0,C0_SR
li t1,~(SR_INTERRUPT_ENABLE_BITS)
STREG t0,C0_SR_OFFSET*4(a0) /* save status register */
STREG t0,C0_SR_OFFSET*R_SZ(a0)
and t0,t1
MTC0 t0,C0_SR /* first disable ie bit (recommended) */
#if __mips == 3
ori t0,SR_EXL|SR_IE /* enable exception level to disable interrupts */
MTC0 t0,C0_SR
ori t0,(SR_EXL|SR_IE) /* enable exception level to disable interrupts */
#endif
MTC0 t0,C0_SR
STREG ra,RA_OFFSET*R_SZ(a0) /* save current context */
STREG sp,SP_OFFSET*R_SZ(a0)
@@ -304,7 +341,7 @@ FRAME(_CPU_Context_switch,sp,0,ra)
STREG s6,S6_OFFSET*R_SZ(a0)
STREG s7,S7_OFFSET*R_SZ(a0)
/*
/* EPC is readonly...
MFC0 t0,C0_EPC
NOP
STREG t0,C0_EPC_OFFSET*R_SZ(a0)
@@ -323,35 +360,64 @@ _CPU_Context_switch_restore:
LDREG s6,S6_OFFSET*R_SZ(a1)
LDREG s7,S7_OFFSET*R_SZ(a1)
/*
/* EPC is readonly...
LDREG t0,C0_EPC_OFFSET*R_SZ(a1)
NOP
MTC0 t0,C0_EPC
*/
LDREG t0, C0_SR_OFFSET*R_SZ(a1)
// NOP
//#if __mips == 3
// 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
//
//#elif __mips == 1
//
// andi t0,(SR_INTERRUPT_ENABLE_BITS) /* we know 0 disabled */
// beq t0,$0,_CPU_Context_1 /* set level from restore context */
// MFC0 t0,C0_SR
// NOP
// or t0,(SR_INTERRUPT_ENABLE_BITS) /* new_sr = old sr with enabled */
// MTC0 t0,C0_SR /* set with enabled */
// NOP
/*
** Incorporate the new thread's FP coprocessor state and interrupt mask/enable
** into the status register. We jump thru the requisite hoops to ensure we
** maintain all other SR bits as global values.
**
** Get the thread's FPU enable, int mask & int enable bits. Although we keep the
** software int enables on a per-task basis, the rtems_task_create
** Interrupt Level & int level manipulation functions cannot enable/disable them,
** so they are automatically enabled for all tasks. To turn them off, a thread
** must itself manipulate the SR register.
*/
#if __mips == 3
li k0,(SR_CU1 | SR_IMASK | SR_EXL | SR_IE)
#elif __mips == 1
li k0,(SR_CU1 | SR_IMASK | SR_IEC)
#endif
and t0,k0
MFC0 t1,C0_SR /* grab the current SR */
not k0 /* invert k0 so we can clear out the SR bits */
and t1,k0
or t0,t1 /* setup the new task's SR value */
MTC0 t0,C0_SR /* and load the new SR */
NOP
#if __mips == 3
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
#elif __mips == 1
andi t0,(SR_INTERRUPT_ENABLE_BITS) /* we know 0 disabled */
beq t0,$0,_CPU_Context_1 /* set level from restore context */
MFC0 t0,C0_SR
NOP
or t0,(SR_INTERRUPT_ENABLE_BITS) /* new_sr = old sr with enabled */
MTC0 t0,C0_SR /* set with enabled */
#endif
_CPU_Context_1:
/* _CPU_Context_1: */
j ra
NOP
ENDFRAME(_CPU_Context_switch)
@@ -450,42 +516,15 @@ FRAME(_ISR_Handler,sp,0,ra)
MFC0 t1,C0_EPC
STREG t0,R_SR*R_SZ(sp)
STREG t1,R_EPC*R_SZ(sp)
#ifdef INSTRUMENT
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t2, _Thread_Executing
nop
sw t2, 0x8001FFF0
sw t0, 0x8001F050
sw t1, 0x8001F054
li t0, 0xdeadbeef
li t1, 0xdeadbeef
li t2, 0xdeadbeef
sw ra, 0x8001F000
sw v0, 0x8001F004
sw v1, 0x8001F008
sw a0, 0x8001F00c
sw a1, 0x8001F010
sw a2, 0x8001F014
sw a3, 0x8001F018
sw t0, 0x8001F01c
sw t1, 0x8001F020
sw t2, 0x8001F024
sw t3, 0x8001F028
sw t4, 0x8001F02c
sw t5, 0x8001F030
sw t6, 0x8001F034
sw t7, 0x8001F038
sw t8, 0x8001F03c
sw t9, 0x8001F040
sw gp, 0x8001F044
sw fp, 0x8001F048
#endif
/* determine if an interrupt generated this exception */
/* determine if an interrupt generated this exception */
MFC0 k0,C0_CAUSE
NOP
@@ -515,9 +554,11 @@ _ISR_Handler_1:
/* Then where did it come from??? */
beq k0,zero,_ISR_Handler_exit
li t2,1 /* set a flag so we process interrupts */
/*
* save some or all context on stack
* may need to save some special interrupt information for exit
@@ -547,10 +588,23 @@ _ISR_Handler_1:
* Call the CPU model or BSP specific routine to decode the
* interrupt source and actually vector to device ISR handlers.
*/
#ifdef INSTRUMENT_ISR_VECTORING
nop
li t1, 1
sw t1, 0x8001e000
#endif
move a0,sp
jal mips_vector_isr_handlers
nop
#ifdef INSTRUMENT_ISR_VECTORING
li t1, 0
sw t1, 0x8001e000
nop
#endif
/*
* --_ISR_Nest_level;
*/
@@ -572,6 +626,14 @@ _ISR_Handler_1:
or t0,t2,t1
bne t0,zero,_ISR_Handler_exit
nop
/*
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
* restore stack
@@ -589,32 +651,35 @@ _ISR_Handler_1:
#ifdef INSTRUMENT
li t0,0x11111111
sw t0,0x8001F104
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0,0x8001FFF4
#endif
/* restore interrupt state from the saved status register,
* if the isr vectoring didn't so we allow nested interrupts to
* occur */
LDREG t0,R_SR*R_SZ(sp)
/*
** Turn on interrupts before entering Thread_Dispatch which
** will run for a while, thus allowing new interrupts to
** be serviced. Observe the Thread_Dispatch_disable_level interlock
** that prevents recursive entry into Thread_Dispatch.
*/
MFC0 t0, C0_SR
NOP
MTC0 t0,C0_SR
rfe
or t0, SR_INTERRUPT_ENABLE_BITS
MTC0 t0, C0_SR
NOP
jal _Thread_Dispatch
NOP
jal _Thread_Dispatch
nop
#ifdef INSTRUMENT
li t0,0x22222222
sw t0,0x8001F100
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0,0x8001FFF8
#endif
/*
* prepare to get out of interrupt
* return from interrupt (maybe to _ISR_Dispatch)
@@ -625,16 +690,19 @@ _ISR_Handler_1:
*/
_ISR_Handler_exit:
LDREG t0, R_SR*R_SZ(sp)
NOP
MTC0 t0, C0_SR
/*
** Skip the SR restore because its a global register. _CPU_Context_switch_restore
** adjusts it according to each task's configuration. If we didn't dispatch, the
** SR value isn't changing, so all we need to do is return.
**
*/
/* restore context from stack */
#ifdef INSTRUMENT
/* restore context from stack */
#ifdef INSTRUMENT_EXECUTING_THREAD
lw t0,_Thread_Executing
nop
sw t0, 0x8001FFF4
sw t0, 0x8001FFFC
#endif
LDREG k0, R_MDLO*R_SZ(sp)
@@ -660,33 +728,11 @@ _ISR_Handler_exit:
LDREG a3, R_A3*R_SZ(sp)
LDREG v1, R_V1*R_SZ(sp)
LDREG v0, R_V0*R_SZ(sp)
#ifdef INSTRUMENT
sw ra, 0x8001F000
sw v0, 0x8001F004
sw v1, 0x8001F008
sw a0, 0x8001F00c
sw a1, 0x8001F010
sw a2, 0x8001F014
sw a3, 0x8001F018
sw t0, 0x8001F01c
sw t1, 0x8001F020
sw t2, 0x8001F024
sw t3, 0x8001F028
sw t4, 0x8001F02c
sw t5, 0x8001F030
sw t6, 0x8001F034
sw t7, 0x8001F038
sw t8, 0x8001F03c
sw t9, 0x8001F040
sw gp, 0x8001F044
sw fp, 0x8001F048
#endif
LDREG k0, R_EPC*R_SZ(sp)
.set noat
LDREG AT, R_AT*R_SZ(sp)
LDREG AT, R_AT*R_SZ(sp)
.set at
ADDIU sp,sp,EXCP_STACK_SIZE
@@ -697,6 +743,7 @@ _ISR_Handler_exit:
.set reorder
ENDFRAME(_ISR_Handler)
FRAME(mips_break,sp,0,ra)
#if 1
break 0x0

View File

@@ -67,7 +67,7 @@ extern "C" {
* one subroutine call is avoided entirely.]
*/
#define CPU_INLINE_ENABLE_DISPATCH TRUE
#define CPU_INLINE_ENABLE_DISPATCH FALSE
/*
* Should the body of the search loops in _Thread_queue_Enqueue_priority
@@ -207,7 +207,7 @@ extern "C" {
* must be saved as part of the preemption.
*/
#define CPU_IDLE_TASK_IS_FP FALSE
#define CPU_IDLE_TASK_IS_FP TRUE
/*
* Should the saving of the floating point registers be deferred
@@ -554,13 +554,6 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (mips_interrupt_number_of_vectors)
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
/*
* This is defined if the port has a special way to report the ISR nesting
* level. Most ports maintain the variable _ISR_Nest_level.
*/
#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
/*
* Should be large enough to run all RTEMS tests. This insures
* that a "reasonable" small application should not have any problems.
@@ -632,7 +625,8 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define _CPU_ISR_Disable( _level ) \
do { \
mips_get_sr( _level ); \
mips_set_sr( (_level) & ~SR_INTERRUPT_ENABLE_BITS ); \
mips_set_sr( _level & ~SR_INTERRUPT_ENABLE_BITS ); \
_level &= SR_INTERRUPT_ENABLE_BITS; \
} while(0)
/*
@@ -643,21 +637,22 @@ extern unsigned int mips_interrupt_number_of_vectors;
#define _CPU_ISR_Enable( _level ) \
do { \
mips_set_sr(_level); \
unsigned int _scratch; \
mips_get_sr( _scratch ); \
mips_set_sr( (_scratch & ~SR_INTERRUPT_ENABLE_BITS) | (_level & SR_INTERRUPT_ENABLE_BITS) ); \
} while(0)
/*
* This temporarily restores the interrupt to _level before immediately
* disabling them again. This is used to divide long RTEMS critical
* sections into two or more parts. The parameter _level is not
* modified.
* modified.
*/
#define _CPU_ISR_Flash( _xlevel ) \
do { \
unsigned int _scratch; \
_CPU_ISR_Enable( _xlevel ); \
_CPU_ISR_Disable( _scratch ); \
_CPU_ISR_Disable( _xlevel ); \
} while(0)
/*
@@ -701,22 +696,52 @@ void _CPU_ISR_Set_level( unsigned32 ); /* in cpu.c */
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
*
* The per-thread status register holds the interrupt enable, FP enable
* and global interrupt enable for that thread. It means each thread can
* enable its own set of interrupts. If interrupts are disabled, RTEMS
* can still dispatch via blocking calls. This is the function of the
* "Interrupt Level", and on the MIPS, it controls the IEC bit and all
* the hardware interrupts as defined in the SR. Software ints
* are automatically enabled for all threads, as they will only occur under
* program control anyhow. Besides, the interrupt level parm is only 8 bits,
* and controlling the software ints plus the others would require 9.
*
* If the Interrupt Level is 0, all ints are on. Otherwise, the
* Interrupt Level should supply a bit pattern to impose on the SR
* interrupt bits; bit 0 applies to the mips1 IEC bit/mips3 EXL&IE, bits 1 thru 6
* apply to the SR register Intr bits from bit 10 thru bit 15. Bit 7 of
* the Interrupt Level parameter is unused at this time.
*
* These are the only per-thread SR bits, the others are maintained
* globally & explicitly preserved by the Context Switch code in cpu_asm.s
*/
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
#if __mips == 3
#define _INTON (SR_EXL | SR_IE)
#endif
#if __mips == 1
#define _INTON SR_IEC
#endif
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, _isr, _entry_point, _is_fp ) \
{ \
unsigned32 _stack_tmp = \
(unsigned32)(_stack_base) + (_size) - CPU_STACK_ALIGNMENT; \
unsigned32 _intlvl = _isr & 0xff; \
_stack_tmp &= ~(CPU_STACK_ALIGNMENT - 1); \
(_the_context)->sp = _stack_tmp; \
(_the_context)->fp = _stack_tmp; \
(_the_context)->ra = (unsigned64)_entry_point; \
(_the_context)->c0_sr = ((_the_context)->c0_sr & 0x0fff0000) | \
((_isr)?0xff00:0xff01) | \
((_is_fp)?0x20000000:0x10000000); \
(_the_context)->c0_sr = ((_intlvl==0)?(0xFF00 | _INTON):( ((_intlvl<<9) & 0xfc00) | \
0x300 | \
((_intlvl & 1)?_INTON:0)) ) | \
SR_CU0 | ((_is_fp)?SR_CU1:0); \
}
/*
* This routine is responsible for somehow restarting the currently
* executing task. If you are lucky, then all that is necessary