2009-04-14 Michael Walle <michael@walle.cc>

* cpu.h: corrected the registers in Context_Control and
	in CPU_Interrupt_frame to correspond to the saved frame in cpu_asm.S
   	Also switched on CPU_ISR_PASSES_FRAME_POINTER.
 	* cpu_asm.S: Moved the restore part of _CPU_Context_switch for
	easier reading.  Fixed _CPU_Context_restore, it now moves the
	argument and branches to a label in _CPU_Context_switch.  Removed
	unnecessary saves of registers in context switch and irq handling.
	Rewrote irq code to call the C helper.  Added some documentation
	* irq.c: New file derived from c4x and nios2.
This commit is contained in:
Joel Sherrill
2009-04-14 13:44:29 +00:00
parent 67ae7bb6f7
commit 7c4c284c4a
5 changed files with 220 additions and 140 deletions
+12
View File
@@ -1,3 +1,15 @@
2009-04-14 Michael Walle <michael@walle.cc>
* cpu.h: corrected the registers in Context_Control and
in CPU_Interrupt_frame to correspond to the saved frame in cpu_asm.S
Also switched on CPU_ISR_PASSES_FRAME_POINTER.
* cpu_asm.S: Moved the restore part of _CPU_Context_switch for
easier reading. Fixed _CPU_Context_restore, it now moves the
argument and branches to a label in _CPU_Context_switch. Removed
unnecessary saves of registers in context switch and irq handling.
Rewrote irq code to call the C helper. Added some documentation
* irq.c: New file derived from c4x and nios2.
2009-04-06 Michael Walle <michael@walle.cc>
* cpu_asm.S: We cannot use any other register than r0 without saving
+1 -1
View File
@@ -12,7 +12,7 @@ include_rtems_score_HEADERS = rtems/score/cpu.h rtems/score/lm32.h \
rtems/score/cpu_asm.h rtems/score/types.h
noinst_LIBRARIES = libscorecpu.a
libscorecpu_a_SOURCES = cpu.c cpu_asm.S
libscorecpu_a_SOURCES = cpu.c cpu_asm.S irq.c
libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
include $(srcdir)/preinstall.am
+119 -135
View File
@@ -13,44 +13,70 @@
*
* Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008,
* Micro-Research Finland Oy
*
* Michael Walle <michael@walle.cc>, 2009
*/
#include <rtems/asm.h>
#include <rtems/score/cpu_asm.h>
#define MICO32_FULL_CONTEXT_SAVE_RESTORE
/* void _CPU_Context_switch(run_context, heir_context)
*
* This routine performs a normal non-FP context switch.
*
* LM32 Specific Information:
*
* XXX document implementation including references if appropriate
* Saves/restores all callee-saved general purpose registers as well as
* the stack pointer, return address and interrupt enable status register
* to/from the context.
*
*/
.globl _CPU_Context_switch
_CPU_Context_switch:
sw (r1+0), r9
sw (r1+4), r10
sw (r1+8), r11
sw (r1+12), r12
sw (r1+16), r13
sw (r1+20), r14
sw (r1+24), r15
sw (r1+28), r16
sw (r1+32), r17
sw (r1+36), r18
sw (r1+40), r19
sw (r1+44), r20
sw (r1+48), r21
sw (r1+52), r22
sw (r1+56), r23
sw (r1+60), r24
sw (r1+64), r25
sw (r1+68), gp
sw (r1+72), fp
sw (r1+76), sp
sw (r1+80), ra
sw (r1+0), r11 /* r1 is the first argument */
sw (r1+4), r12
sw (r1+8), r13
sw (r1+12), r14
sw (r1+16), r15
sw (r1+20), r16
sw (r1+24), r17
sw (r1+28), r18
sw (r1+32), r19
sw (r1+36), r20
sw (r1+40), r21
sw (r1+44), r22
sw (r1+48), r23
sw (r1+52), r24
sw (r1+56), r25
sw (r1+60), gp
sw (r1+64), fp
sw (r1+68), sp
sw (r1+72), ra
rcsr r3, IE
sw (r1+76), r3
_CPU_Context_switch_restore:
lw r11, (r2+0) /* r2 is the second argument */
lw r12, (r2+4)
lw r13, (r2+8)
lw r14, (r2+12)
lw r15, (r2+16)
lw r16, (r2+20)
lw r17, (r2+24)
lw r18, (r2+28)
lw r19, (r2+32)
lw r20, (r2+36)
lw r21, (r2+40)
lw r22, (r2+44)
lw r23, (r2+48)
lw r24, (r2+52)
lw r25, (r2+56)
lw gp, (r2+60)
lw fp, (r2+64)
lw sp, (r2+68)
lw ra, (r2+72)
lw r3, (r2+76)
wcsr IE, r3
ret
/*
* _CPU_Context_restore
@@ -58,112 +84,90 @@ _CPU_Context_switch:
* 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.
*
* LM32 Specific Information:
*
* XXX document implementation including references if appropriate
* Moves argument #1 to #2 and branches to the restore part of the
* context switch code above.
*/
.globl _CPU_Context_restore
_CPU_Context_restore:
lw r9, (r2+0)
lw r10, (r2+4)
lw r11, (r2+8)
lw r12, (r2+12)
lw r13, (r2+16)
lw r14, (r2+20)
lw r15, (r2+24)
lw r16, (r2+28)
lw r17, (r2+32)
lw r18, (r2+36)
lw r19, (r2+40)
lw r20, (r2+44)
lw r21, (r2+48)
lw r22, (r2+52)
lw r23, (r2+56)
lw r24, (r2+60)
lw r25, (r2+64)
lw gp, (r2+68)
lw fp, (r2+72)
lw ra, (r2+80)
/* Stack pointer must be restored last, in case it has been updated */
lw sp, (r2+76)
nop
ret
/* void __ISR_Handler()
mv r2, r1
bi _CPU_Context_switch_restore
/* void _ISR_Handler()
*
* This routine provides the RTEMS interrupt management.
*
* LM32 Specific Information:
*
* XXX document implementation including references if appropriate
* Saves all the caller-saved general purpose registers as well as the
* return address, exception return address and breakpoint return address
* (the latter may be unnecessary) onto the stack, which is either the task
* stack (in case of a interrupted task) or the interrupt stack (if an
* interrupt was interrupted).
* After that, it figures out the pending interrupt with the highest
* priority and calls the main ISR handler written in C, which in turn
* handles interrupt nesting, software interrupt stack setup etc and
* finally calls the user ISR.
* At the end the saved registers are restored.
*
*/
.globl _ISR_Handler
_ISR_Handler:
xor r0, r0, r0
addi sp, sp, -128
sw (sp+4), r1
sw (sp+8), r2
sw (sp+12), r3
sw (sp+16), r4
sw (sp+20), r5
sw (sp+24), r6
sw (sp+28), r7
sw (sp+32), r8
sw (sp+36), r9
sw (sp+40), r10
#ifdef MICO32_FULL_CONTEXT_SAVE_RESTORE
sw (sp+44), r11
sw (sp+48), r12
sw (sp+52), r13
sw (sp+56), r14
sw (sp+60), r15
sw (sp+64), r16
sw (sp+68), r17
sw (sp+72), r18
sw (sp+76), r19
sw (sp+80), r20
sw (sp+84), r21
sw (sp+88), r22
sw (sp+92), r23
sw (sp+96), r24
sw (sp+100), r25
sw (sp+104), r26
sw (sp+108), r27
#endif
sw (sp+116), ra
sw (sp+120), ea
sw (sp+124), ba
xor r0, r0, r0
addi sp, sp, -52
sw (sp+4), r1
sw (sp+8), r2
sw (sp+12), r3
sw (sp+16), r4
sw (sp+20), r5
sw (sp+24), r6
sw (sp+28), r7
sw (sp+32), r8
sw (sp+36), r9
sw (sp+40), r10
sw (sp+44), ra
sw (sp+48), ea
sw (sp+52), ba
/* Scan through (IP & IM) bits starting from LSB until irq found */
rcsr r2,IP
rcsr r3,IM
and r4,r2,r3
or r1,r0,r0
ori r5,r0,1
find_irq:
and r6,r4,r5
bne r6,r0,found_irq
sli r5,r5,1
addi r1,r1,1
bne r5,r0,find_irq
/* If we end up here there was no interrupt - this should never
happen! */
bi exit_isr
/*
* Scan through IP & IM bits starting from LSB until irq vector is
* found. The vector is stored in r1, which is the first argument for
* __ISR_Handler.
*/
rcsr r2, IP
rcsr r3, IM
mv r1, r0 /* r1: counter for the vector number */
and r2, r2, r3 /* r2: pending irqs, which are enabled */
mvi r3, 1 /* r3: register for the walking 1 */
/*
* If r2 is zero, there was no interrupt.
* This should never happen!
*/
be r2, r0, exit_isr
find_irq:
and r4, r2, r3
bne r4, r0, found_irq
sli r3, r3, 1
addi r1, r1, 1
bi find_irq
found_irq:
.extern _ISR_Vector_table
sli r1,r1,2
mvhi r7,hi(_ISR_Vector_table)
ori r7,r7,lo(_ISR_Vector_table)
lw r6,(r7+0)
add r6,r6,r1
lw r5,(r6+0)
call r5
/*
* Call __ISR_Handler for further processing.
* r1 is the vector number, calculated above
* r2 is the pointer to the CPU_Interrupt_frame
*/
addi r2, sp, 4
.extern __ISR_Handler
mvhi r3, hi(__ISR_Handler)
ori r3, r3, lo(__ISR_Handler)
call r3
exit_isr:
/* Restore the saved registers */
lw r1, (sp+4)
lw r2, (sp+8)
lw r3, (sp+12)
@@ -174,29 +178,9 @@ exit_isr:
lw r8, (sp+32)
lw r9, (sp+36)
lw r10, (sp+40)
#ifdef MICO32_FULL_CONTEXT_SAVE_RESTORE
lw r11, (sp+44)
lw r12, (sp+48)
lw r13, (sp+52)
lw r14, (sp+56)
lw r15, (sp+60)
lw r16, (sp+64)
lw r17, (sp+68)
lw r18, (sp+72)
lw r19, (sp+76)
lw r20, (sp+80)
lw r21, (sp+84)
lw r22, (sp+88)
lw r23, (sp+92)
lw r24, (sp+96)
lw r25, (sp+100)
lw r26, (sp+104)
lw r27, (sp+108)
#endif
lw ra, (sp+116)
lw ea, (sp+120)
lw ba, (sp+124)
addi sp, sp, 128
nop
lw ra, (sp+44)
lw ea, (sp+48)
lw ba, (sp+52)
addi sp, sp, 52
eret
+83
View File
@@ -0,0 +1,83 @@
/*
* lm32 interrupt handler
*
* Derived from c4x/irq.c and nios2/irq.c
*
* COPYRIGHT (c) 1989-2009.
* 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$
*/
#include <rtems/system.h>
#include <rtems/score/cpu.h>
#include <rtems/score/isr.h>
#include <rtems/score/thread.h>
/*
* This routine provides the RTEMS interrupt management.
*
* Upon entry, interrupts are disabled
*/
#if( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
unsigned long *_old_stack_ptr;
#endif
register unsigned long *stack_ptr asm("sp");
void __ISR_Handler(uint32_t vector, CPU_Interrupt_frame *ifr)
{
register uint32_t level;
/* Interrupts are disabled upon entry to this Handler */
_Thread_Dispatch_disable_level++;
#if( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
if ( _ISR_Nest_level == 0 ) {
/* Install irq stack */
_old_stack_ptr = stack_ptr;
stack_ptr = _CPU_Interrupt_stack_high - 4;
}
#endif
_ISR_Nest_level++;
if ( _ISR_Vector_table[ vector] )
{
(*_ISR_Vector_table[ vector ])(vector, ifr);
};
/* Make sure that interrupts are disabled again */
_CPU_ISR_Disable( level );
_ISR_Nest_level--;
#if( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
if( _ISR_Nest_level == 0)
stack_ptr = _old_stack_ptr;
#endif
_Thread_Dispatch_disable_level--;
_CPU_ISR_Enable( level );
if ( _ISR_Nest_level )
return;
if ( _Thread_Dispatch_disable_level ) {
_ISR_Signals_to_thread_executing = FALSE;
return;
}
if ( _Context_Switch_necessary || _ISR_Signals_to_thread_executing ) {
_ISR_Signals_to_thread_executing = FALSE;
_Thread_Dispatch();
}
}
+5 -4
View File
@@ -175,7 +175,7 @@ extern "C" {
*
* XXX document implementation including references if appropriate
*/
#define CPU_ISR_PASSES_FRAME_POINTER 0
#define CPU_ISR_PASSES_FRAME_POINTER 1
/**
* @def CPU_HARDWARE_FP
@@ -462,8 +462,6 @@ extern "C" {
* to another.
*/
typedef struct {
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t r13;
@@ -483,6 +481,7 @@ typedef struct {
uint32_t fp;
uint32_t sp;
uint32_t ra;
uint32_t ie;
} Context_Control;
/**
@@ -520,9 +519,11 @@ typedef struct {
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t ra;
uint32_t gp;
uint32_t ba;
uint32_t ea;
} CPU_Interrupt_frame;
/**