forked from Imagelibrary/rtems
SPARC port passes all tests
This commit is contained in:
@@ -68,7 +68,8 @@ The following persons/organizations have made contributions:
|
||||
to port RTEMS to the SPARC V7 architecture for use with their ERC32
|
||||
radiation-hardened CPU. Jiri Gaisler (jgais@wd.estec.esa.nl) deserves
|
||||
special thanks for championing this port within the ESA was well as
|
||||
for developing the SPARC Instruction Simulator used to test this port.
|
||||
for developing and supporting the SPARC Instruction Simulator used to
|
||||
develop and test this port.
|
||||
|
||||
Finally, the RTEMS project would like to thank those who have contributed
|
||||
to the other free software efforts which RTEMS utilizes. The primary RTEMS
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
#define __RINGBUF_H__
|
||||
|
||||
#ifndef RINGBUF_QUEUE_LENGTH
|
||||
#define RINGBUF_QUEUE_LENGTH 200
|
||||
#define RINGBUF_QUEUE_LENGTH 128
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char buffer[RINGBUF_QUEUE_LENGTH];
|
||||
int head;
|
||||
int tail;
|
||||
volatile int head;
|
||||
volatile int tail;
|
||||
} Ring_buffer_t;
|
||||
|
||||
#define Ring_buffer_Initialize( _buffer ) \
|
||||
@@ -27,16 +27,27 @@ typedef struct {
|
||||
#define Ring_buffer_Is_empty( _buffer ) \
|
||||
( (_buffer)->head == (_buffer)->tail )
|
||||
|
||||
#define Ring_buffer_Is_full( _buffer ) \
|
||||
( (_buffer)->head == ((_buffer)->tail + 1) % RINGBUF_QUEUE_LENGTH )
|
||||
|
||||
#define Ring_buffer_Add_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->tail = ((_buffer)->tail+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define Ring_buffer_Remove_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->head = ((_buffer)->head+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,8 +60,7 @@ EXTERN Objects_Information _POSIX_Interrupt_Handlers_Information;
|
||||
* interrupt handlers installed on each vector.
|
||||
*/
|
||||
|
||||
EXTERN POSIX_Interrupt_Control
|
||||
_POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
EXTERN POSIX_Interrupt_Control _POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _POSIX_Interrupt_Manager_initialization
|
||||
|
||||
@@ -60,8 +60,7 @@ EXTERN Objects_Information _POSIX_Interrupt_Handlers_Information;
|
||||
* interrupt handlers installed on each vector.
|
||||
*/
|
||||
|
||||
EXTERN POSIX_Interrupt_Control
|
||||
_POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
EXTERN POSIX_Interrupt_Control _POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _POSIX_Interrupt_Manager_initialization
|
||||
|
||||
@@ -108,3 +108,205 @@ rtems_status_code rtems_event_receive(
|
||||
_Thread_Enable_dispatch();
|
||||
return( _Thread_Executing->Wait.return_code );
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Seize
|
||||
*
|
||||
* This routine attempts to satisfy the requested event condition
|
||||
* for the running thread.
|
||||
*
|
||||
* Input parameters:
|
||||
* event_in - the event condition to satisfy
|
||||
* option_set - acquire event options
|
||||
* ticks - interval to wait
|
||||
* event_out - pointer to event set output area
|
||||
*
|
||||
* Output parameters: NONE
|
||||
* *event_out - event set output area filled in
|
||||
*
|
||||
* INTERRUPT LATENCY:
|
||||
* available
|
||||
* wait
|
||||
* check sync
|
||||
*/
|
||||
|
||||
void _Event_Seize(
|
||||
rtems_event_set event_in,
|
||||
rtems_option option_set,
|
||||
rtems_interval ticks,
|
||||
rtems_event_set *event_out
|
||||
)
|
||||
{
|
||||
Thread_Control *executing;
|
||||
rtems_event_set seized_events;
|
||||
rtems_event_set pending_events;
|
||||
ISR_Level level;
|
||||
RTEMS_API_Control *api;
|
||||
|
||||
executing = _Thread_Executing;
|
||||
executing->Wait.return_code = RTEMS_SUCCESSFUL;
|
||||
|
||||
api = executing->API_Extensions[ THREAD_API_RTEMS ];
|
||||
|
||||
_ISR_Disable( level );
|
||||
pending_events = api->pending_events;
|
||||
seized_events = _Event_sets_Get( pending_events, event_in );
|
||||
|
||||
if ( !_Event_sets_Is_empty( seized_events ) &&
|
||||
(seized_events == event_in || _Options_Is_any( option_set )) ) {
|
||||
api->pending_events =
|
||||
_Event_sets_Clear( pending_events, seized_events );
|
||||
_ISR_Enable( level );
|
||||
*event_out = seized_events;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _Options_Is_no_wait( option_set ) ) {
|
||||
_ISR_Enable( level );
|
||||
executing->Wait.return_code = RTEMS_UNSATISFIED;
|
||||
*event_out = seized_events;
|
||||
return;
|
||||
}
|
||||
|
||||
_Event_Sync = TRUE;
|
||||
executing->Wait.option = (unsigned32) option_set;
|
||||
executing->Wait.count = (unsigned32) event_in;
|
||||
executing->Wait.return_argument = event_out;
|
||||
|
||||
_ISR_Enable( level );
|
||||
_Thread_Set_state( executing, STATES_WAITING_FOR_EVENT );
|
||||
|
||||
if ( ticks ) {
|
||||
_Watchdog_Initialize(
|
||||
&executing->Timer,
|
||||
_Event_Timeout,
|
||||
executing->Object.id,
|
||||
NULL
|
||||
);
|
||||
_Watchdog_Insert_ticks(
|
||||
&executing->Timer,
|
||||
ticks,
|
||||
WATCHDOG_NO_ACTIVATE
|
||||
);
|
||||
}
|
||||
|
||||
_ISR_Disable( level );
|
||||
if ( _Event_Sync == TRUE ) {
|
||||
_Event_Sync = FALSE;
|
||||
if ( ticks )
|
||||
_Watchdog_Activate( &executing->Timer );
|
||||
_ISR_Enable( level );
|
||||
return;
|
||||
}
|
||||
_ISR_Enable( level );
|
||||
(void) _Watchdog_Remove( &executing->Timer );
|
||||
_Thread_Unblock( executing );
|
||||
return;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Surrender
|
||||
*
|
||||
* This routines remove a thread from the specified threadq.
|
||||
*
|
||||
* Input parameters:
|
||||
* the_thread - pointer to thread to be dequeued
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*
|
||||
* INTERRUPT LATENCY:
|
||||
* before flash
|
||||
* after flash
|
||||
* check sync
|
||||
*/
|
||||
|
||||
void _Event_Surrender(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
ISR_Level level;
|
||||
rtems_event_set pending_events;
|
||||
rtems_event_set event_condition;
|
||||
rtems_event_set seized_events;
|
||||
rtems_option option_set;
|
||||
RTEMS_API_Control *api;
|
||||
|
||||
api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
|
||||
|
||||
option_set = (rtems_option) the_thread->Wait.option;
|
||||
|
||||
_ISR_Disable( level );
|
||||
pending_events = api->pending_events;
|
||||
event_condition = (rtems_event_set) the_thread->Wait.count;
|
||||
|
||||
seized_events = _Event_sets_Get( pending_events, event_condition );
|
||||
|
||||
if ( !_Event_sets_Is_empty( seized_events ) ) {
|
||||
if ( _States_Is_waiting_for_event( the_thread->current_state ) ) {
|
||||
if ( seized_events == event_condition || _Options_Is_any( option_set ) ) {
|
||||
api->pending_events =
|
||||
_Event_sets_Clear( pending_events, seized_events );
|
||||
*(rtems_event_set *)the_thread->Wait.return_argument = seized_events;
|
||||
|
||||
_ISR_Flash( level );
|
||||
|
||||
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
|
||||
_ISR_Enable( level );
|
||||
_Thread_Unblock( the_thread );
|
||||
}
|
||||
else {
|
||||
_Watchdog_Deactivate( &the_thread->Timer );
|
||||
_ISR_Enable( level );
|
||||
(void) _Watchdog_Remove( &the_thread->Timer );
|
||||
_Thread_Unblock( the_thread );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( _Thread_Is_executing( the_thread ) && _Event_Sync == TRUE ) {
|
||||
if ( seized_events == event_condition || _Options_Is_any( option_set ) ) {
|
||||
api->pending_events = _Event_sets_Clear( pending_events,seized_events );
|
||||
*(rtems_event_set *)the_thread->Wait.return_argument = seized_events;
|
||||
_Event_Sync = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ISR_Enable( level );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Timeout
|
||||
*
|
||||
* This routine processes a thread which timeouts while waiting to
|
||||
* receive an event_set. It is called by the watchdog handler.
|
||||
*
|
||||
* Input parameters:
|
||||
* id - thread id
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*/
|
||||
|
||||
void _Event_Timeout(
|
||||
Objects_Id id,
|
||||
void *ignored
|
||||
)
|
||||
{
|
||||
Thread_Control *the_thread;
|
||||
Objects_Locations location;
|
||||
|
||||
the_thread = _Thread_Get( id, &location );
|
||||
switch ( location ) {
|
||||
case OBJECTS_ERROR:
|
||||
case OBJECTS_REMOTE: /* impossible */
|
||||
break;
|
||||
case OBJECTS_LOCAL:
|
||||
the_thread->Wait.return_code = RTEMS_TIMEOUT;
|
||||
_Thread_Unblock( the_thread );
|
||||
_Thread_Unnest_dispatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +279,7 @@ EXTERN void *_CPU_Interrupt_stack_high;
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (HPPA_INTERRUPT_MAX)
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Don't be chintzy here; we don't want to debug these problems
|
||||
@@ -387,7 +388,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_new_level, _entry_point ) \
|
||||
_new_level, _entry_point, _is_fp ) \
|
||||
do { \
|
||||
unsigned32 _stack; \
|
||||
\
|
||||
@@ -456,6 +457,9 @@ void hppa_cpu_halt(unsigned32 type_of_halt, unsigned32 the_error);
|
||||
* is implemented in software.
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE FALSE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA FALSE
|
||||
|
||||
int hppa_rtems_ffs(unsigned int value);
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
_output = hppa_rtems_ffs(_value)
|
||||
@@ -477,7 +481,7 @@ int hppa_rtems_ffs(unsigned int value);
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 1 << (_bit_number) )
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
@@ -144,6 +144,7 @@ EXTERN void *_CPU_Interrupt_stack_high;
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Minimum size of a thread's stack.
|
||||
@@ -208,7 +209,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
#define CPU_EFLAGS_INTERRUPTS_OFF 0x00003002
|
||||
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_isr, _entry_point ) \
|
||||
_isr, _entry_point, _is_fp ) \
|
||||
do { \
|
||||
unsigned32 _stack; \
|
||||
\
|
||||
@@ -265,6 +266,9 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
* + scan for the highest numbered (MSB) set in a 16 bit bitfield
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE FALSE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA FALSE
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
{ \
|
||||
register unsigned16 __value_in_register = (_value); \
|
||||
@@ -292,7 +296,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 1 << (_bit_number) )
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
/* functions */
|
||||
|
||||
@@ -186,6 +186,7 @@ EXTERN void *_CPU_Interrupt_stack_high;
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Minimum size of a thread's stack.
|
||||
@@ -252,7 +253,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_isr, _entry ) \
|
||||
_isr, _entry, _is_fp ) \
|
||||
{ CPU_Call_frame *_texit_frame; \
|
||||
unsigned32 _mask; \
|
||||
unsigned32 _base_pc; \
|
||||
@@ -318,6 +319,9 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
* + scan for the highest numbered (MSB) set in a 16 bit bitfield
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE FALSE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA FALSE
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
{ unsigned32 _search = (_value); \
|
||||
\
|
||||
@@ -341,7 +345,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 0x8000 >> (_bit_number) )
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
( 15 - (_priority) )
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
@@ -176,6 +176,7 @@ extern char _VBR[];
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Minimum size of a thread's stack.
|
||||
@@ -237,7 +238,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_isr, _entry_point ) \
|
||||
_isr, _entry_point, _is_fp ) \
|
||||
do { \
|
||||
void *_stack; \
|
||||
\
|
||||
@@ -301,6 +302,9 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
* have a real 16 bit wide bitfield which operates "correctly."
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE FALSE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA FALSE
|
||||
|
||||
#if ( M68K_HAS_BFFFO == 1 )
|
||||
#ifdef NO_UNINITIALIZED_WARNINGS
|
||||
|
||||
@@ -327,7 +331,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
#else
|
||||
|
||||
/* duplicates BFFFO results for 16 bits (i.e., 15-(_priority) in
|
||||
_CPU_Priority_Bits_index is not needed), handles the 0 case, and
|
||||
_CPU_Priority_bits_index is not needed), handles the 0 case, and
|
||||
does not molest _value -- jsg */
|
||||
#ifndef m68000
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
@@ -386,7 +390,7 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 0x8000 >> (_bit_number) )
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
@@ -174,9 +174,6 @@ SYM (_ISR_Handler):
|
||||
* in place to know what vector we got on a 68000 core.
|
||||
*/
|
||||
|
||||
.global SYM (_ISR_Exit)
|
||||
SYM (_ISR_Exit):
|
||||
|
||||
subql #1,SYM (_ISR_Nest_level) | one less nest level
|
||||
subql #1,SYM (_Thread_Dispatch_disable_level)
|
||||
| unnest multitasking
|
||||
|
||||
@@ -413,6 +413,7 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 32
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Should be large enough to run all RTEMS tests. This insures
|
||||
@@ -536,7 +537,7 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_isr, _entry_point ) \
|
||||
_isr, _entry_point, _is_fp ) \
|
||||
{ \
|
||||
}
|
||||
|
||||
@@ -621,11 +622,11 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
*
|
||||
* RTEMS guarantees that (1) will never happen so it is not a concern.
|
||||
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
|
||||
* _CPU_Priority_Bits_index(). These three form a set of routines
|
||||
* _CPU_Priority_bits_index(). These three form a set of routines
|
||||
* which must logically operate together. Bits in the _value are
|
||||
* set and cleared based on masks built by _CPU_Priority_mask().
|
||||
* The basic major and minor values calculated by _Priority_Major()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_bits_index()
|
||||
* to properly range between the values returned by the "find first bit"
|
||||
* instruction. This makes it possible for _Priority_Get_highest() to
|
||||
* calculate the major and directly index into the minor table.
|
||||
@@ -660,11 +661,18 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
* bit set
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
|
||||
|
||||
#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
{ \
|
||||
(_output) = 0; /* do something to prevent warnings */ \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* end of Bitfield handler macros */
|
||||
|
||||
/*
|
||||
@@ -673,9 +681,13 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
* for that routine.
|
||||
*/
|
||||
|
||||
#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
|
||||
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 1 << (_bit_number) )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This routine translates the bit numbers returned by
|
||||
* _CPU_Bitfield_Find_first_bit() into something suitable for use as
|
||||
@@ -683,9 +695,13 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
* for that routine.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
|
||||
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
#endif
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
/* functions */
|
||||
|
||||
@@ -542,6 +542,7 @@ EXTERN struct {
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (PPC_INTERRUPT_MAX)
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Should be large enough to run all RTEMS tests. This insures
|
||||
@@ -682,7 +683,7 @@ EXTERN struct {
|
||||
|
||||
#if PPC_ABI == PPC_ABI_POWEROPEN
|
||||
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
|
||||
_isr, _entry_point ) \
|
||||
_isr, _entry_point, _is_fp ) \
|
||||
{ \
|
||||
unsigned32 sp, *desc; \
|
||||
\
|
||||
@@ -816,11 +817,11 @@ EXTERN struct {
|
||||
*
|
||||
* RTEMS guarantees that (1) will never happen so it is not a concern.
|
||||
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
|
||||
* _CPU_Priority_Bits_index(). These three form a set of routines
|
||||
* _CPU_Priority_bits_index(). These three form a set of routines
|
||||
* which must logically operate together. Bits in the _value are
|
||||
* set and cleared based on masks built by _CPU_Priority_mask().
|
||||
* The basic major and minor values calculated by _Priority_Major()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_bits_index()
|
||||
* to properly range between the values returned by the "find first bit"
|
||||
* instruction. This makes it possible for _Priority_Get_highest() to
|
||||
* calculate the major and directly index into the minor table.
|
||||
@@ -855,6 +856,9 @@ EXTERN struct {
|
||||
* bit set
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE FALSE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA FALSE
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
{ \
|
||||
asm volatile ("cntlzw %0, %1" : "=r" ((_output)), "=r" ((_value)) : \
|
||||
@@ -879,7 +883,7 @@ EXTERN struct {
|
||||
* for that routine.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
#define _CPU_Priority_bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
118
c/src/exec/score/cpu/sparc/README
Normal file
118
c/src/exec/score/cpu/sparc/README
Normal file
@@ -0,0 +1,118 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
This file discusses SPARC specific issues which are important to
|
||||
this port. The primary topics in this file are:
|
||||
|
||||
+ Global Register Usage
|
||||
+ Stack Frame
|
||||
+ EF bit in the PSR
|
||||
|
||||
|
||||
Global Register Usage
|
||||
=====================
|
||||
|
||||
This information on register usage is based heavily on a comment in the
|
||||
file gcc-2.7.0/config/sparc/sparc.h in the the gcc 2.7.0 source.
|
||||
|
||||
+ g0 is hardwired to 0
|
||||
+ On non-v9 systems:
|
||||
- g1 is free to use as temporary.
|
||||
- g2-g4 are reserved for applications. Gcc normally uses them as
|
||||
temporaries, but this can be disabled via the -mno-app-regs option.
|
||||
- g5 through g7 are reserved for the operating system.
|
||||
+ On v9 systems:
|
||||
- g1 and g5 are free to use as temporaries.
|
||||
- g2-g4 are reserved for applications (the compiler will not normally use
|
||||
them, but they can be used as temporaries with -mapp-regs).
|
||||
- g6-g7 are reserved for the operating system.
|
||||
|
||||
NOTE: As of gcc 2.7.0 register g1 was used in the following scenarios:
|
||||
|
||||
+ as a temporary by the 64 bit sethi pattern
|
||||
+ when restoring call-preserved registers in large stack frames
|
||||
|
||||
RTEMS places no constraints on the usage of the global registers. Although
|
||||
gcc assumes that either g5-g7 (non-V9) or g6-g7 (V9) are reserved for the
|
||||
operating system, RTEMS does not assume any special use for them.
|
||||
|
||||
|
||||
|
||||
Stack Frame
|
||||
===========
|
||||
|
||||
The stack grows downward (i.e. to lower addresses) on the SPARC architecture.
|
||||
|
||||
The following is the organization of the stack frame:
|
||||
|
||||
|
||||
|
||||
| ............... |
|
||||
fp | |
|
||||
+-------------------------------+
|
||||
| |
|
||||
| Local registers, temporaries, |
|
||||
| and saved floats | x bytes
|
||||
| |
|
||||
sp + x +-------------------------------+
|
||||
| |
|
||||
| outgoing parameters past |
|
||||
| the sixth one | x bytes
|
||||
| |
|
||||
sp + 92 +-------------------------------+ *
|
||||
| | *
|
||||
| area for callee to save | *
|
||||
| register arguments | * 24 bytes
|
||||
| | *
|
||||
sp + 68 +-------------------------------+ *
|
||||
| | *
|
||||
| structure return pointer | * 4 bytes
|
||||
| | *
|
||||
sp + 64 +-------------------------------+ *
|
||||
| | *
|
||||
| local register set | * 32 bytes
|
||||
| | *
|
||||
sp + 32 +-------------------------------+ *
|
||||
| | *
|
||||
| input register set | * 32 bytes
|
||||
| | *
|
||||
sp +-------------------------------+ *
|
||||
|
||||
|
||||
* = minimal stack frame
|
||||
|
||||
x = optional components
|
||||
|
||||
EF bit in the PSR
|
||||
=================
|
||||
|
||||
The EF (enable floating point unit) in the PSR is utilized in this port to
|
||||
prevent non-floating point tasks from performing floating point
|
||||
operations. This bit is maintained as part of the integer context.
|
||||
However, the floating point context is switched BEFORE the integer
|
||||
context. Thus the EF bit in place at the time of the FP switch may
|
||||
indicate that FP operations are disabled. This occurs on certain task
|
||||
switches, when the EF bit will be 0 for the outgoing task and thus a fault
|
||||
will be generated on the first FP operation of the FP context save.
|
||||
|
||||
The remedy for this is to enable FP access as the first step in both the
|
||||
save and restore of the FP context area. This bit will be subsequently
|
||||
reloaded by the integer context switch.
|
||||
|
||||
Two of the scenarios which demonstrate this problem are outlined below:
|
||||
|
||||
1. When the first FP task is switched to. The system tasks are not FP and
|
||||
thus would be unable to restore the FP context of the incoming task.
|
||||
|
||||
2. On a deferred FP context switch. In this case, the system might switch
|
||||
from FP Task A to non-FP Task B and then to FP Task C. In this scenario,
|
||||
the floating point state must technically be saved by a non-FP task.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
*/
|
||||
|
||||
#define ASM
|
||||
|
||||
#include <rtems/score/sparc.h>
|
||||
#include <rtems/score/cpu.h>
|
||||
|
||||
/*
|
||||
* Recent versions of GNU cpp define variables which indicate the
|
||||
@@ -37,7 +39,9 @@
|
||||
* have to define these as appropriate.
|
||||
*/
|
||||
|
||||
/* XXX This does not appear to work on gcc 2.7.0 on the sparc */
|
||||
/* XXX __USER_LABEL_PREFIX__ and __REGISTER_PREFIX__ do not work on gcc 2.7.0 */
|
||||
/* XXX The following ifdef magic fixes the problem but results in a warning */
|
||||
/* XXX when compiling assembly code. */
|
||||
#undef __USER_LABEL_PREFIX__
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__ _
|
||||
@@ -91,6 +95,16 @@
|
||||
#define PUBLIC(sym) .globl SYM (sym)
|
||||
#define EXTERN(sym) .globl SYM (sym)
|
||||
|
||||
/*
|
||||
* Entry for traps which jump to a programmer-specified trap handler.
|
||||
*/
|
||||
|
||||
#define TRAP(_vector, _handler) \
|
||||
mov %psr, %l0 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
mov _vector, %l3
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
|
||||
@@ -7,52 +7,115 @@
|
||||
#include <rtems/system.h>
|
||||
#include <rtems/score/isr.h>
|
||||
|
||||
/* _CPU_Initialize
|
||||
#if defined(erc32)
|
||||
#include <erc32.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This initializes the set of opcodes placed in each trap
|
||||
* table entry. The routine which installs a handler is responsible
|
||||
* for filling in the fields for the _handler address and the _vector
|
||||
* trap type.
|
||||
*
|
||||
* The constants following this structure are masks for the fields which
|
||||
* must be filled in when the handler is installed.
|
||||
*/
|
||||
|
||||
const CPU_Trap_table_entry _CPU_Trap_slot_template = {
|
||||
0xa1480000, /* mov %psr, %l0 */
|
||||
0x29000000, /* sethi %hi(_handler), %l4 */
|
||||
0x81c52000, /* jmp %l4 + %lo(_handler) */
|
||||
0xa6102000 /* mov _vector, %l3 */
|
||||
};
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Initialize
|
||||
*
|
||||
* This routine performs processor dependent initialization.
|
||||
*
|
||||
* INPUT PARAMETERS:
|
||||
* Input Parameters:
|
||||
* cpu_table - CPU table to initialize
|
||||
* thread_dispatch - address of disptaching routine
|
||||
*
|
||||
* Output Parameters: NONE
|
||||
*
|
||||
* NOTE: There is no need to save the pointer to the thread dispatch routine.
|
||||
* The SPARC's assembly code can reference it directly with no problems.
|
||||
*/
|
||||
|
||||
|
||||
void _CPU_Initialize(
|
||||
rtems_cpu_table *cpu_table,
|
||||
void (*thread_dispatch) /* ignored on this CPU */
|
||||
)
|
||||
{
|
||||
void *pointer;
|
||||
unsigned32 trap_table_start;
|
||||
unsigned32 tbr_value;
|
||||
CPU_Trap_table_entry *old_tbr;
|
||||
CPU_Trap_table_entry *trap_table;
|
||||
|
||||
/*
|
||||
* The thread_dispatch argument is the address of the entry point
|
||||
* for the routine called at the end of an ISR once it has been
|
||||
* decided a context switch is necessary. On some compilation
|
||||
* systems it is difficult to call a high-level language routine
|
||||
* from assembly. This allows us to trick these systems.
|
||||
*
|
||||
* If you encounter this problem save the entry point in a CPU
|
||||
* dependent variable.
|
||||
* Install the executive's trap table. All entries from the original
|
||||
* trap table are copied into the executive's trap table. This is essential
|
||||
* since this preserves critical trap handlers such as the window underflow
|
||||
* and overflow handlers. It is the responsibility of the BSP to provide
|
||||
* install these in the initial trap table.
|
||||
*/
|
||||
|
||||
_CPU_Thread_dispatch_pointer = thread_dispatch;
|
||||
trap_table_start = (unsigned32) &_CPU_Trap_Table_area;
|
||||
if (trap_table_start & (SPARC_TRAP_TABLE_ALIGNMENT-1))
|
||||
trap_table_start = (trap_table_start + SPARC_TRAP_TABLE_ALIGNMENT) &
|
||||
~(SPARC_TRAP_TABLE_ALIGNMENT-1);
|
||||
|
||||
trap_table = (CPU_Trap_table_entry *) trap_table_start;
|
||||
|
||||
sparc_get_tbr( tbr_value );
|
||||
|
||||
old_tbr = (CPU_Trap_table_entry *) (tbr_value & 0xfffff000);
|
||||
|
||||
memcpy( trap_table, (void *) old_tbr, 256 * sizeof( CPU_Trap_table_entry ) );
|
||||
|
||||
sparc_set_tbr( trap_table_start );
|
||||
|
||||
/*
|
||||
* If there is not an easy way to initialize the FP context
|
||||
* during Context_Initialize, then it is usually easier to
|
||||
* save an "uninitialized" FP context here and copy it to
|
||||
* the task's during Context_Initialize.
|
||||
* This seems to be the most appropriate way to obtain an initial
|
||||
* FP context on the SPARC. The NULL fp context is copied it to
|
||||
* the task's FP context during Context_Initialize.
|
||||
*/
|
||||
|
||||
pointer = &_CPU_Null_fp_context;
|
||||
_CPU_Context_save_fp( &pointer );
|
||||
|
||||
/*
|
||||
* Grab our own copy of the user's CPU table.
|
||||
*/
|
||||
|
||||
_CPU_Table = *cpu_table;
|
||||
|
||||
#if defined(erc32)
|
||||
|
||||
/*
|
||||
* ERC32 specific initialization
|
||||
*/
|
||||
|
||||
_ERC32_MEC_Timer_Control_Mirror = 0;
|
||||
ERC32_MEC.Timer_Control = 0;
|
||||
|
||||
ERC32_MEC.Control |= ERC32_CONFIGURATION_POWER_DOWN_ALLOWED;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_Get_level
|
||||
*
|
||||
* Input Parameters: NONE
|
||||
*
|
||||
* Output Parameters:
|
||||
* returns the current interrupt level (PIL field of the PSR)
|
||||
*/
|
||||
|
||||
unsigned32 _CPU_ISR_Get_level( void )
|
||||
@@ -64,134 +127,263 @@ unsigned32 _CPU_ISR_Get_level( void )
|
||||
return level;
|
||||
}
|
||||
|
||||
/* _CPU_ISR_install_vector
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_install_raw_handler
|
||||
*
|
||||
* This routine installs the specified handler as a "raw" non-executive
|
||||
* supported trap handler (a.k.a. interrupt service routine).
|
||||
*
|
||||
* Input Parameters:
|
||||
* vector - trap table entry number plus synchronous
|
||||
* vs. asynchronous information
|
||||
* new_handler - address of the handler to be installed
|
||||
* old_handler - pointer to an address of the handler previously installed
|
||||
*
|
||||
* Output Parameters: NONE
|
||||
* *new_handler - address of the handler previously installed
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* On the SPARC, there are really only 256 vectors. However, the executive
|
||||
* has no easy, fast, reliable way to determine which traps are synchronous
|
||||
* and which are asynchronous. By default, synchronous traps return to the
|
||||
* instruction which caused the interrupt. So if you install a software
|
||||
* trap handler as an executive interrupt handler (which is desirable since
|
||||
* RTEMS takes care of window and register issues), then the executive needs
|
||||
* to know that the return address is to the trap rather than the instruction
|
||||
* following the trap.
|
||||
*
|
||||
* So vectors 0 through 255 are treated as regular asynchronous traps which
|
||||
* provide the "correct" return address. Vectors 256 through 512 are assumed
|
||||
* by the executive to be synchronous and to require that the return address
|
||||
* be fudged.
|
||||
*
|
||||
* If you use this mechanism to install a trap handler which must reexecute
|
||||
* the instruction which caused the trap, then it should be installed as
|
||||
* an asynchronous trap. This will avoid the executive changing the return
|
||||
* address.
|
||||
*/
|
||||
|
||||
void _CPU_ISR_install_raw_handler(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
)
|
||||
{
|
||||
unsigned32 real_vector;
|
||||
CPU_Trap_table_entry *tbr;
|
||||
CPU_Trap_table_entry *slot;
|
||||
unsigned32 u32_tbr;
|
||||
unsigned32 u32_handler;
|
||||
|
||||
/*
|
||||
* Get the "real" trap number for this vector ignoring the synchronous
|
||||
* versus asynchronous indicator included with our vector numbers.
|
||||
*/
|
||||
|
||||
real_vector = SPARC_REAL_TRAP_NUMBER( vector );
|
||||
|
||||
/*
|
||||
* Get the current base address of the trap table and calculate a pointer
|
||||
* to the slot we are interested in.
|
||||
*/
|
||||
|
||||
sparc_get_tbr( u32_tbr );
|
||||
|
||||
u32_tbr &= 0xfffff000;
|
||||
|
||||
tbr = (CPU_Trap_table_entry *) u32_tbr;
|
||||
|
||||
slot = &tbr[ real_vector ];
|
||||
|
||||
/*
|
||||
* Get the address of the old_handler from the trap table.
|
||||
*
|
||||
* NOTE: The old_handler returned will be bogus if it does not follow
|
||||
* the RTEMS model.
|
||||
*/
|
||||
|
||||
#define HIGH_BITS_MASK 0xFFFFFC00
|
||||
#define HIGH_BITS_SHIFT 10
|
||||
#define LOW_BITS_MASK 0x000003FF
|
||||
|
||||
if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
|
||||
u32_handler =
|
||||
((slot->sethi_of_handler_to_l4 & HIGH_BITS_MASK) << HIGH_BITS_SHIFT) |
|
||||
(slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
|
||||
*old_handler = (proc_ptr) u32_handler;
|
||||
} else
|
||||
*old_handler = 0;
|
||||
|
||||
/*
|
||||
* Copy the template to the slot and then fix it.
|
||||
*/
|
||||
|
||||
*slot = _CPU_Trap_slot_template;
|
||||
|
||||
u32_handler = (unsigned32) new_handler;
|
||||
|
||||
slot->mov_vector_l3 |= vector;
|
||||
slot->sethi_of_handler_to_l4 |=
|
||||
(u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
|
||||
slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_install_vector
|
||||
*
|
||||
* This kernel routine installs the RTEMS handler for the
|
||||
* specified vector.
|
||||
*
|
||||
* Input parameters:
|
||||
* vector - interrupt vector number
|
||||
* old_handler - former ISR for this vector number
|
||||
* new_handler - replacement ISR for this vector number
|
||||
* old_handler - pointer to former ISR for this vector number
|
||||
*
|
||||
* Output parameters: NONE
|
||||
* Output parameters:
|
||||
* *old_handler - former ISR for this vector number
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void _CPU_ISR_install_vector(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
)
|
||||
{
|
||||
*old_handler = _ISR_Vector_table[ vector ];
|
||||
unsigned32 real_vector;
|
||||
proc_ptr ignored;
|
||||
|
||||
/*
|
||||
* If the interrupt vector table is a table of pointer to isr entry
|
||||
* points, then we need to install the appropriate RTEMS interrupt
|
||||
* handler for this vector number.
|
||||
* Get the "real" trap number for this vector ignoring the synchronous
|
||||
* versus asynchronous indicator included with our vector numbers.
|
||||
*/
|
||||
|
||||
real_vector = SPARC_REAL_TRAP_NUMBER( vector );
|
||||
|
||||
/*
|
||||
* Return the previous ISR handler.
|
||||
*/
|
||||
|
||||
*old_handler = _ISR_Vector_table[ real_vector ];
|
||||
|
||||
/*
|
||||
* Install the wrapper so this ISR can be invoked properly.
|
||||
*/
|
||||
|
||||
_CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
|
||||
|
||||
/*
|
||||
* We put the actual user ISR address in '_ISR_vector_table'. This will
|
||||
* be used by the _ISR_Handler so the user gets control.
|
||||
*/
|
||||
|
||||
_ISR_Vector_table[ vector ] = new_handler;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Install_interrupt_stack
|
||||
*/
|
||||
|
||||
void _CPU_Install_interrupt_stack( void )
|
||||
{
|
||||
_ISR_Vector_table[ real_vector ] = new_handler;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Context_Initialize
|
||||
*
|
||||
* This kernel routine initializes the basic non-FP context area associated
|
||||
* with each thread.
|
||||
*
|
||||
* Input parameters:
|
||||
* the_context - pointer to the context area
|
||||
* stack_base - address of memory for the SPARC
|
||||
* size - size in bytes of the stack area
|
||||
* new_level - interrupt level for this context area
|
||||
* entry_point - the starting execution point for this this context
|
||||
* is_fp - TRUE if this context is associated with an FP thread
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following constants assist in building a thread's initial context.
|
||||
*/
|
||||
|
||||
#define CPU_FRAME_SIZE (112) /* based on disassembled test code */
|
||||
#define ADDR_ADJ_OFFSET -8
|
||||
|
||||
void _CPU_Context_Initialize(
|
||||
Context_Control *_the_context,
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
Context_Control *the_context,
|
||||
unsigned32 *stack_base,
|
||||
unsigned32 size,
|
||||
unsigned32 new_level,
|
||||
void *entry_point,
|
||||
boolean is_fp
|
||||
)
|
||||
{
|
||||
unsigned32 jmp_addr;
|
||||
unsigned32 _stack_high; /* highest "stack aligned" address */
|
||||
unsigned32 _the_size;
|
||||
unsigned32 stack_high; /* highest "stack aligned" address */
|
||||
unsigned32 the_size;
|
||||
unsigned32 tmp_psr;
|
||||
|
||||
jmp_addr = (unsigned32) _entry_point;
|
||||
|
||||
/*
|
||||
* On CPUs with stacks which grow down (i.e. SPARC), we build the stack
|
||||
* based on the _stack_high address.
|
||||
* based on the stack_high address.
|
||||
*/
|
||||
|
||||
_stack_high = ((unsigned32)(_stack_base) + _size);
|
||||
_stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
|
||||
stack_high = ((unsigned32)(stack_base) + size);
|
||||
stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
|
||||
|
||||
_the_size = _size & ~(CPU_STACK_ALIGNMENT - 1);
|
||||
the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
|
||||
|
||||
/* XXX following code is based on unix port */
|
||||
/*
|
||||
* XXX SPARC port needs a diagram like this one...
|
||||
* See /usr/include/sys/stack.h in Solaris 2.3 for a nice
|
||||
* diagram of the stack.
|
||||
* See the README in this directory for a diagram of the stack.
|
||||
*/
|
||||
|
||||
_the_context->o7 = jmp_addr + ADDR_ADJ_OFFSET;
|
||||
_the_context->o6 = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
|
||||
_the_context->i6 = (unsigned32)(_stack_high);
|
||||
#if 0
|
||||
_the_context->rp = jmp_addr + ADDR_ADJ_OFFSET;
|
||||
_the_context->sp = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
|
||||
_the_context->fp = (unsigned32)(_stack_high);
|
||||
#endif
|
||||
the_context->o7 = ((unsigned32) entry_point) - 8;
|
||||
the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
|
||||
the_context->i6_fp = stack_high;
|
||||
|
||||
_the_context->wim = 0x01;
|
||||
/*
|
||||
* Build the PSR for the task. Most everything can be 0 and the
|
||||
* CWP is corrected during the context switch.
|
||||
*
|
||||
* The EF bit determines if the floating point unit is available.
|
||||
* The FPU is ONLY enabled if the context is associated with an FP task
|
||||
* and this SPARC model has an FPU.
|
||||
*/
|
||||
|
||||
sparc_get_psr( tmp_psr );
|
||||
tmp_psr &= ~SPARC_PIL_MASK;
|
||||
tmp_psr |= (((_new_level) << 8) & SPARC_PIL_MASK);
|
||||
tmp_psr = (tmp_psr & ~0x07) | 0x07; /* XXX should use num windows */
|
||||
_the_context->psr = tmp_psr;
|
||||
tmp_psr &= ~SPARC_PSR_PIL_MASK;
|
||||
tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
|
||||
tmp_psr &= ~SPARC_PSR_EF_MASK; /* disabled by default */
|
||||
|
||||
#if (SPARC_HAS_FPU == 1)
|
||||
/*
|
||||
* If this bit is not set, then a task gets a fault when it accesses
|
||||
* a floating point register. This is a nice way to detect floating
|
||||
* point tasks which are not currently declared as such.
|
||||
*/
|
||||
|
||||
if ( is_fp )
|
||||
tmp_psr |= SPARC_PSR_EF_MASK;
|
||||
#endif
|
||||
the_context->psr = tmp_psr;
|
||||
}
|
||||
|
||||
/*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.
|
||||
* Some SPARC implementations have low power, sleep, or idle modes. This
|
||||
* tries to take advantage of those models.
|
||||
*/
|
||||
|
||||
#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
|
||||
|
||||
/*
|
||||
* This is the implementation for the erc32.
|
||||
*
|
||||
* NOTE: Low power mode was enabled at initialization time.
|
||||
*/
|
||||
|
||||
#if defined(erc32)
|
||||
|
||||
void _CPU_Internal_threads_Idle_thread_body( void )
|
||||
{
|
||||
|
||||
for( ; ; )
|
||||
/* insert your "halt" instruction here */ ;
|
||||
while (1) {
|
||||
ERC32_MEC.Power_Down = 0; /* value is irrelevant */
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* cpu.h
|
||||
*
|
||||
* This include file contains information pertaining to the XXX
|
||||
* processor.
|
||||
* This include file contains information pertaining to the port of
|
||||
* the executive to the SPARC processor.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
@@ -25,16 +25,6 @@ extern "C" {
|
||||
*
|
||||
* If TRUE, then they are inlined.
|
||||
* If FALSE, then a subroutine call is made.
|
||||
*
|
||||
* Basically this is an example of the classic trade-off of size
|
||||
* versus speed. Inlining the call (TRUE) typically increases the
|
||||
* size of the executive while speeding up the enabling of dispatching.
|
||||
* [NOTE: In general, the _Thread_Dispatch_disable_level will
|
||||
* only be 0 or 1 unless you are in an interrupt handler and that
|
||||
* interrupt handler invokes the executive.] When not inlined
|
||||
* something calls _Thread_Enable_dispatch which in turns calls
|
||||
* _Thread_Dispatch. If the enable dispatch is inlined, then
|
||||
* one subroutine call is avoided entirely.]
|
||||
*/
|
||||
|
||||
#define CPU_INLINE_ENABLE_DISPATCH TRUE
|
||||
@@ -48,13 +38,10 @@ extern "C" {
|
||||
* If TRUE, then the loops are unrolled.
|
||||
* If FALSE, then the loops are not unrolled.
|
||||
*
|
||||
* The primary factor in making this decision is the cost of disabling
|
||||
* and enabling interrupts (_ISR_Flash) versus the cost of rest of the
|
||||
* body of the loop. On some CPUs, the flash is more expensive than
|
||||
* one iteration of the loop body. In this case, it might be desirable
|
||||
* to unroll the loop. It is important to note that on some CPUs, this
|
||||
* code is the longest interrupt disable period in the executive. So it is
|
||||
* necessary to strike a balance when setting this parameter.
|
||||
* This parameter could go either way on the SPARC. The interrupt flash
|
||||
* code is relatively lengthy given the requirements for nops following
|
||||
* writes to the psr. But if the clock speed were high enough, this would
|
||||
* not represent a great deal of time.
|
||||
*/
|
||||
|
||||
#define CPU_UNROLL_ENQUEUE_PRIORITY TRUE
|
||||
@@ -65,25 +52,11 @@ extern "C" {
|
||||
* If TRUE, then a stack is allocated in _Interrupt_Manager_initialization.
|
||||
* If FALSE, nothing is done.
|
||||
*
|
||||
* If the CPU supports a dedicated interrupt stack in hardware,
|
||||
* then it is generally the responsibility of the BSP to allocate it
|
||||
* and set it up.
|
||||
*
|
||||
* If the CPU does not support a dedicated interrupt stack, then
|
||||
* the porter has two options: (1) execute interrupts on the stack of
|
||||
* the interrupted task, and (2) have the executive manage a dedicated
|
||||
* interrupt stack.
|
||||
*
|
||||
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
|
||||
*
|
||||
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
|
||||
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
|
||||
* possible that both are FALSE for a particular CPU. Although it
|
||||
* is unclear what that would imply about the interrupt processing
|
||||
* procedure on that CPU.
|
||||
* The SPARC does not have a dedicated HW interrupt stack and one has
|
||||
* been implemented in SW.
|
||||
*/
|
||||
|
||||
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK FALSE /* XXX */
|
||||
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE
|
||||
|
||||
/*
|
||||
* Does this CPU have hardware support for a dedicated interrupt stack?
|
||||
@@ -91,25 +64,16 @@ extern "C" {
|
||||
* If TRUE, then it must be installed during initialization.
|
||||
* If FALSE, then no installation is performed.
|
||||
*
|
||||
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
|
||||
*
|
||||
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
|
||||
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
|
||||
* possible that both are FALSE for a particular CPU. Although it
|
||||
* is unclear what that would imply about the interrupt processing
|
||||
* procedure on that CPU.
|
||||
* The SPARC does not have a dedicated HW interrupt stack.
|
||||
*/
|
||||
|
||||
#define CPU_HAS_HARDWARE_INTERRUPT_STACK TRUE /* XXX */
|
||||
#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE
|
||||
|
||||
/*
|
||||
* Do we allocate a dedicated interrupt stack in the Interrupt Manager?
|
||||
*
|
||||
* If TRUE, then the memory is allocated during initialization.
|
||||
* If FALSE, then the memory is allocated during initialization.
|
||||
*
|
||||
* This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE
|
||||
* or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE.
|
||||
*/
|
||||
|
||||
#define CPU_ALLOCATE_INTERRUPT_STACK TRUE
|
||||
@@ -119,15 +83,6 @@ extern "C" {
|
||||
*
|
||||
* If TRUE, then the FLOATING_POINT task attribute is supported.
|
||||
* If FALSE, then the FLOATING_POINT task attribute is ignored.
|
||||
*
|
||||
* If there is a FP coprocessor such as the i387 or mc68881, then
|
||||
* the answer is TRUE.
|
||||
*
|
||||
* The macro name "SPARC_HAS_FPU" should be made CPU specific.
|
||||
* It indicates whether or not this CPU model has FP support. For
|
||||
* example, it would be possible to have an i386_nofp CPU model
|
||||
* which set this to false to indicate that you have an i386 without
|
||||
* an i387 and wish to leave floating point support out.
|
||||
*/
|
||||
|
||||
#if ( SPARC_HAS_FPU == 1 )
|
||||
@@ -141,15 +96,6 @@ extern "C" {
|
||||
*
|
||||
* If TRUE, then the FLOATING_POINT task attribute is assumed.
|
||||
* If FALSE, then the FLOATING_POINT task attribute is followed.
|
||||
*
|
||||
* So far, the only CPU in which this option has been used is the
|
||||
* HP PA-RISC. The HP C compiler and gcc both implicitly use the
|
||||
* floating point registers to perform integer multiplies. If
|
||||
* a function which you would not think utilize the FP unit DOES,
|
||||
* then one can not easily predict which tasks will use the FP hardware.
|
||||
* In this case, this option should be TRUE.
|
||||
*
|
||||
* If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
|
||||
*/
|
||||
|
||||
#define CPU_ALL_TASKS_ARE_FP FALSE
|
||||
@@ -160,10 +106,6 @@ extern "C" {
|
||||
* If TRUE, then the IDLE task is created as a FLOATING_POINT task
|
||||
* and it has a floating point context which is switched in and out.
|
||||
* If FALSE, then the IDLE task does not have a floating point context.
|
||||
*
|
||||
* Setting this to TRUE negatively impacts the time required to preempt
|
||||
* the IDLE task from an interrupt because the floating point context
|
||||
* must be saved as part of the preemption.
|
||||
*/
|
||||
|
||||
#define CPU_IDLE_TASK_IS_FP FALSE
|
||||
@@ -181,17 +123,6 @@ extern "C" {
|
||||
* point task is switched out and restored when the next floating point
|
||||
* task is restored. The state of the floating point registers between
|
||||
* those two operations is not specified.
|
||||
*
|
||||
* If the floating point context does NOT have to be saved as part of
|
||||
* interrupt dispatching, then it should be safe to set this to TRUE.
|
||||
*
|
||||
* Setting this flag to TRUE results in using a different algorithm
|
||||
* for deciding when to save and restore the floating point context.
|
||||
* The deferred FP switch algorithm minimizes the number of times
|
||||
* the FP context is saved and restored. The FP context is not saved
|
||||
* until a context switch is made to another, different FP task.
|
||||
* Thus in a system with only one FP task, the FP context will never
|
||||
* be saved or restored.
|
||||
*/
|
||||
|
||||
#define CPU_USE_DEFERRED_FP_SWITCH TRUE
|
||||
@@ -205,19 +136,13 @@ extern "C" {
|
||||
*
|
||||
* If FALSE, then use the generic IDLE thread body if the BSP does
|
||||
* not provide one.
|
||||
*
|
||||
* This is intended to allow for supporting processors which have
|
||||
* a low power or idle mode. When the IDLE thread is executed, then
|
||||
* the CPU can be powered down.
|
||||
*
|
||||
* The order of precedence for selecting the IDLE thread body is:
|
||||
*
|
||||
* 1. BSP provided
|
||||
* 2. CPU dependent (if provided)
|
||||
* 3. generic (if no BSP and no CPU dependent)
|
||||
*/
|
||||
|
||||
#if (SPARC_HAS_LOW_POWER_MODE == 1)
|
||||
#define CPU_PROVIDES_IDLE_THREAD_BODY TRUE
|
||||
#else
|
||||
#define CPU_PROVIDES_IDLE_THREAD_BODY FALSE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Does the stack grow up (toward higher addresses) or down
|
||||
@@ -225,6 +150,8 @@ extern "C" {
|
||||
*
|
||||
* If TRUE, then the grows upward.
|
||||
* If FALSE, then the grows toward smaller addresses.
|
||||
*
|
||||
* The stack grows to lower addresses on the SPARC.
|
||||
*/
|
||||
|
||||
#define CPU_STACK_GROWS_UP FALSE
|
||||
@@ -236,17 +163,8 @@ extern "C" {
|
||||
* the minimum requirements of the compiler in order to have as
|
||||
* much of the critical data area as possible in a cache line.
|
||||
*
|
||||
* The placement of this macro in the declaration of the variables
|
||||
* is based on the syntactically requirements of the GNU C
|
||||
* "__attribute__" extension. For example with GNU C, use
|
||||
* the following to force a structures to a 32 byte boundary.
|
||||
*
|
||||
* __attribute__ ((aligned (32)))
|
||||
*
|
||||
* NOTE: Currently only the Priority Bit Map table uses this feature.
|
||||
* To benefit from using this, the data must be heavily
|
||||
* used so it will stay in the cache and used frequently enough
|
||||
* in the executive to justify turning this on.
|
||||
* The SPARC does not appear to have particularly strict alignment
|
||||
* requirements. This value was chosen to take advantages of caches.
|
||||
*/
|
||||
|
||||
#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (16)))
|
||||
@@ -255,18 +173,80 @@ extern "C" {
|
||||
* The following defines the number of bits actually used in the
|
||||
* interrupt field of the task mode. How those bits map to the
|
||||
* CPU interrupt levels is defined by the routine _CPU_ISR_Set_level().
|
||||
*
|
||||
* The SPARC has 16 interrupt levels in the PIL field of the PSR.
|
||||
*/
|
||||
|
||||
#define CPU_MODES_INTERRUPT_MASK 0x0000000F
|
||||
|
||||
/*
|
||||
* Processor defined structures
|
||||
*
|
||||
* Examples structures include the descriptor tables from the i386
|
||||
* and the processor control structure on the i960ca.
|
||||
* This structure represents the organization of the minimum stack frame
|
||||
* for the SPARC. More framing information is required in certain situaions
|
||||
* such as when there are a large number of out parameters or when the callee
|
||||
* must save floating point registers.
|
||||
*/
|
||||
|
||||
/* XXX may need to put some structures here. */
|
||||
#ifndef ASM
|
||||
|
||||
typedef struct {
|
||||
unsigned32 l0;
|
||||
unsigned32 l1;
|
||||
unsigned32 l2;
|
||||
unsigned32 l3;
|
||||
unsigned32 l4;
|
||||
unsigned32 l5;
|
||||
unsigned32 l6;
|
||||
unsigned32 l7;
|
||||
unsigned32 i0;
|
||||
unsigned32 i1;
|
||||
unsigned32 i2;
|
||||
unsigned32 i3;
|
||||
unsigned32 i4;
|
||||
unsigned32 i5;
|
||||
unsigned32 i6_fp;
|
||||
unsigned32 i7;
|
||||
void *structure_return_address;
|
||||
/*
|
||||
* The following are for the callee to save the register arguments in
|
||||
* should this be necessary.
|
||||
*/
|
||||
unsigned32 saved_arg0;
|
||||
unsigned32 saved_arg1;
|
||||
unsigned32 saved_arg2;
|
||||
unsigned32 saved_arg3;
|
||||
unsigned32 saved_arg4;
|
||||
unsigned32 saved_arg5;
|
||||
unsigned32 pad0;
|
||||
} CPU_Minimum_stack_frame;
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
#define CPU_STACK_FRAME_L0_OFFSET 0x00
|
||||
#define CPU_STACK_FRAME_L1_OFFSET 0x04
|
||||
#define CPU_STACK_FRAME_L2_OFFSET 0x08
|
||||
#define CPU_STACK_FRAME_L3_OFFSET 0x0c
|
||||
#define CPU_STACK_FRAME_L4_OFFSET 0x10
|
||||
#define CPU_STACK_FRAME_L5_OFFSET 0x14
|
||||
#define CPU_STACK_FRAME_L6_OFFSET 0x18
|
||||
#define CPU_STACK_FRAME_L7_OFFSET 0x1c
|
||||
#define CPU_STACK_FRAME_I0_OFFSET 0x20
|
||||
#define CPU_STACK_FRAME_I1_OFFSET 0x24
|
||||
#define CPU_STACK_FRAME_I2_OFFSET 0x28
|
||||
#define CPU_STACK_FRAME_I3_OFFSET 0x2c
|
||||
#define CPU_STACK_FRAME_I4_OFFSET 0x30
|
||||
#define CPU_STACK_FRAME_I5_OFFSET 0x34
|
||||
#define CPU_STACK_FRAME_I6_FP_OFFSET 0x38
|
||||
#define CPU_STACK_FRAME_I7_OFFSET 0x3c
|
||||
#define CPU_STRUCTURE_RETURN_ADDRESS_OFFSET 0x40
|
||||
#define CPU_STACK_FRAME_SAVED_ARG0_OFFSET 0x44
|
||||
#define CPU_STACK_FRAME_SAVED_ARG1_OFFSET 0x48
|
||||
#define CPU_STACK_FRAME_SAVED_ARG2_OFFSET 0x4c
|
||||
#define CPU_STACK_FRAME_SAVED_ARG3_OFFSET 0x50
|
||||
#define CPU_STACK_FRAME_SAVED_ARG4_OFFSET 0x54
|
||||
#define CPU_STACK_FRAME_SAVED_ARG5_OFFSET 0x58
|
||||
#define CPU_STACK_FRAME_PAD0_OFFSET 0x5c
|
||||
|
||||
#define CPU_MINIMUM_STACK_FRAME_SIZE 0x60
|
||||
|
||||
/*
|
||||
* Contexts
|
||||
@@ -280,35 +260,21 @@ extern "C" {
|
||||
* 2. floating point task stuff:: Context_Control_fp
|
||||
* 3. special interrupt level context :: Context_Control_interrupt
|
||||
*
|
||||
* On some processors, it is cost-effective to save only the callee
|
||||
* preserved registers during a task context switch. This means
|
||||
* that the ISR code needs to save those registers which do not
|
||||
* persist across function calls. It is not mandatory to make this
|
||||
* distinctions between the caller/callee saves registers for the
|
||||
* purpose of minimizing context saved during task switch and on interrupts.
|
||||
* If the cost of saving extra registers is minimal, simplicity is the
|
||||
* choice. Save the same context on interrupt entry as for tasks in
|
||||
* this case.
|
||||
*
|
||||
* Additionally, if gdb is to be made aware of tasks for this CPU, then
|
||||
* care should be used in designing the context area.
|
||||
*
|
||||
* On some CPUs with hardware floating point support, the Context_Control_fp
|
||||
* structure will not be used or it simply consist of an array of a
|
||||
* fixed number of bytes. This is done when the floating point context
|
||||
* is dumped by a "FP save context" type instruction and the format
|
||||
* is not really defined by the CPU. In this case, there is no need
|
||||
* to figure out the exact format -- only the size. Of course, although
|
||||
* this is enough information for context switches, it is probably not
|
||||
* enough for a debugger such as gdb. But that is another problem.
|
||||
* On the SPARC, we are relatively conservative in that we save most
|
||||
* of the CPU state in the context area. The ET (enable trap) bit and
|
||||
* the CWP (current window pointer) fields of the PSR are considered
|
||||
* system wide resources and are not maintained on a per-thread basis.
|
||||
*/
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/* XXX */
|
||||
typedef struct {
|
||||
unsigned32 g0;
|
||||
unsigned32 g1;
|
||||
/*
|
||||
* Using a double g0_g1 will put everything in this structure on a
|
||||
* double word boundary which allows us to use double word loads
|
||||
* and stores safely in the context switch.
|
||||
*/
|
||||
double g0_g1;
|
||||
unsigned32 g2;
|
||||
unsigned32 g3;
|
||||
unsigned32 g4;
|
||||
@@ -331,7 +297,7 @@ typedef struct {
|
||||
unsigned32 i3;
|
||||
unsigned32 i4;
|
||||
unsigned32 i5;
|
||||
unsigned32 i6;
|
||||
unsigned32 i6_fp;
|
||||
unsigned32 i7;
|
||||
|
||||
unsigned32 o0;
|
||||
@@ -340,10 +306,9 @@ typedef struct {
|
||||
unsigned32 o3;
|
||||
unsigned32 o4;
|
||||
unsigned32 o5;
|
||||
unsigned32 o6;
|
||||
unsigned32 o6_sp;
|
||||
unsigned32 o7;
|
||||
|
||||
unsigned32 wim;
|
||||
unsigned32 psr;
|
||||
} Context_Control;
|
||||
|
||||
@@ -377,7 +342,7 @@ typedef struct {
|
||||
#define I3_OFFSET 0x4C
|
||||
#define I4_OFFSET 0x50
|
||||
#define I5_OFFSET 0x54
|
||||
#define I6_OFFSET 0x58
|
||||
#define I6_FP_OFFSET 0x58
|
||||
#define I7_OFFSET 0x5C
|
||||
|
||||
#define O0_OFFSET 0x60
|
||||
@@ -386,15 +351,19 @@ typedef struct {
|
||||
#define O3_OFFSET 0x6C
|
||||
#define O4_OFFSET 0x70
|
||||
#define O5_OFFSET 0x74
|
||||
#define O6_OFFSET 0x78
|
||||
#define O6_SP_OFFSET 0x78
|
||||
#define O7_OFFSET 0x7C
|
||||
|
||||
#define WIM_OFFSET 0x80
|
||||
#define PSR_OFFSET 0x84
|
||||
#define PSR_OFFSET 0x80
|
||||
|
||||
#define CONTEXT_CONTROL_SIZE 0x84
|
||||
|
||||
/*
|
||||
* The floating point context area.
|
||||
*/
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/* XXX */
|
||||
typedef struct {
|
||||
double f0_f1;
|
||||
double f2_f3;
|
||||
@@ -439,10 +408,39 @@ typedef struct {
|
||||
#define F3O_F31_OFFSET 0x78
|
||||
#define FSR_OFFSET 0x80
|
||||
|
||||
#define CONTEXT_CONTROL_FP_SIZE 0x84
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* Context saved on stack for an interrupt.
|
||||
*
|
||||
* NOTE: The PSR, PC, and NPC are only saved in this structure for the
|
||||
* benefit of the user's handler.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned32 special_interrupt_register_XXX;
|
||||
CPU_Minimum_stack_frame Stack_frame;
|
||||
unsigned32 psr;
|
||||
unsigned32 pc;
|
||||
unsigned32 npc;
|
||||
unsigned32 g1;
|
||||
unsigned32 g2;
|
||||
unsigned32 g3;
|
||||
unsigned32 g4;
|
||||
unsigned32 g5;
|
||||
unsigned32 g6;
|
||||
unsigned32 g7;
|
||||
unsigned32 i0;
|
||||
unsigned32 i1;
|
||||
unsigned32 i2;
|
||||
unsigned32 i3;
|
||||
unsigned32 i4;
|
||||
unsigned32 i5;
|
||||
unsigned32 i6_fp;
|
||||
unsigned32 i7;
|
||||
unsigned32 y;
|
||||
unsigned32 pad0_offset;
|
||||
} CPU_Interrupt_frame;
|
||||
|
||||
#endif /* ASM */
|
||||
@@ -451,11 +449,34 @@ typedef struct {
|
||||
* Offsets of fields with CPU_Interrupt_frame for assembly routines.
|
||||
*/
|
||||
|
||||
#define ISF_STACK_FRAME_OFFSET 0x00
|
||||
#define ISF_PSR_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x00
|
||||
#define ISF_PC_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x04
|
||||
#define ISF_NPC_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x08
|
||||
#define ISF_G1_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x0c
|
||||
#define ISF_G2_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x10
|
||||
#define ISF_G3_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x14
|
||||
#define ISF_G4_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x18
|
||||
#define ISF_G5_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x1c
|
||||
#define ISF_G6_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x20
|
||||
#define ISF_G7_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x24
|
||||
#define ISF_I0_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x28
|
||||
#define ISF_I1_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x2c
|
||||
#define ISF_I2_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x30
|
||||
#define ISF_I3_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x34
|
||||
#define ISF_I4_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x38
|
||||
#define ISF_I5_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x3c
|
||||
#define ISF_I6_FP_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x40
|
||||
#define ISF_I7_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x44
|
||||
#define ISF_Y_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x48
|
||||
#define ISF_PAD0_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x4c
|
||||
|
||||
#define CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE CPU_MINIMUM_STACK_FRAME_SIZE + 0x50
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* The following table contains the information required to configure
|
||||
* the XXX processor specific parameters.
|
||||
* the processor specific parameters.
|
||||
*
|
||||
* NOTE: The interrupt_stack_size field is required if
|
||||
* CPU_ALLOCATE_INTERRUPT_STACK is defined as TRUE.
|
||||
@@ -472,61 +493,97 @@ typedef struct {
|
||||
boolean do_zero_of_workspace;
|
||||
unsigned32 interrupt_stack_size;
|
||||
unsigned32 extra_system_initialization_stack;
|
||||
unsigned32 some_other_cpu_dependent_info_XXX;
|
||||
} rtems_cpu_table;
|
||||
|
||||
/*
|
||||
* This variable is optional. It is used on CPUs on which it is difficult
|
||||
* to generate an "uninitialized" FP context. It is filled in by
|
||||
* _CPU_Initialize and copied into the task's FP context area during
|
||||
* _CPU_Context_Initialize.
|
||||
* This variable is contains the initialize context for the FP unit.
|
||||
* It is filled in by _CPU_Initialize and copied into the task's FP
|
||||
* context area during _CPU_Context_Initialize.
|
||||
*/
|
||||
|
||||
EXTERN Context_Control_fp _CPU_Null_fp_context CPU_STRUCTURE_ALIGNMENT;
|
||||
|
||||
/*
|
||||
* On some CPUs, software managed interrupt stack is supported.
|
||||
* This stack is allocated by the Interrupt Manager and the switch
|
||||
* is performed in _ISR_Handler. These variables contain pointers
|
||||
* to the lowest and highest addresses in the chunk of memory allocated
|
||||
* for the interrupt stack. Since it is unknown whether the stack
|
||||
* grows up or down (in general), this give the CPU dependent
|
||||
* code the option of picking the version it wants to use.
|
||||
* code the option of picking the version it wants to use. Thus
|
||||
* both must be present if either is.
|
||||
*
|
||||
* NOTE: These two variables are required if the macro
|
||||
* CPU_HAS_SOFTWARE_INTERRUPT_STACK is defined as TRUE.
|
||||
* The SPARC supports a software based interrupt stack and these
|
||||
* are required.
|
||||
*/
|
||||
|
||||
EXTERN void *_CPU_Interrupt_stack_low;
|
||||
EXTERN void *_CPU_Interrupt_stack_high;
|
||||
|
||||
#if defined(erc32)
|
||||
|
||||
/*
|
||||
* With some compilation systems, it is difficult if not impossible to
|
||||
* call a high-level language routine from assembly language. This
|
||||
* is especially true of commercial Ada compilers and name mangling
|
||||
* C++ ones. This variable can be optionally defined by the CPU porter
|
||||
* and contains the address of the routine _Thread_Dispatch. This
|
||||
* can make it easier to invoke that routine at the end of the interrupt
|
||||
* sequence (if a dispatch is necessary).
|
||||
* ERC32 Specific Variables
|
||||
*/
|
||||
|
||||
EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
EXTERN unsigned32 _ERC32_MEC_Timer_Control_Mirror;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Nothing prevents the porter from declaring more CPU specific variables.
|
||||
* The following type defines an entry in the SPARC's trap table.
|
||||
*
|
||||
* NOTE: The instructions chosen are RTEMS dependent although one is
|
||||
* obligated to use two of the four instructions to perform a
|
||||
* long jump. The other instructions load one register with the
|
||||
* trap type (a.k.a. vector) and another with the psr.
|
||||
*/
|
||||
|
||||
/* XXX: if needed, put more variables here */
|
||||
typedef struct {
|
||||
unsigned32 mov_psr_l0; /* mov %psr, %l0 */
|
||||
unsigned32 sethi_of_handler_to_l4; /* sethi %hi(_handler), %l4 */
|
||||
unsigned32 jmp_to_low_of_handler_plus_l4; /* jmp %l4 + %lo(_handler) */
|
||||
unsigned32 mov_vector_l3; /* mov _vector, %l3 */
|
||||
} CPU_Trap_table_entry;
|
||||
|
||||
/*
|
||||
* The size of the floating point context area. On some CPUs this
|
||||
* will not be a "sizeof" because the format of the floating point
|
||||
* area is not defined -- only the size is. This is usually on
|
||||
* CPUs with a "floating point save context" instruction.
|
||||
* This is the set of opcodes for the instructions loaded into a trap
|
||||
* table entry. The routine which installs a handler is responsible
|
||||
* for filling in the fields for the _handler address and the _vector
|
||||
* trap type.
|
||||
*
|
||||
* The constants following this structure are masks for the fields which
|
||||
* must be filled in when the handler is installed.
|
||||
*/
|
||||
|
||||
extern const CPU_Trap_table_entry _CPU_Trap_slot_template;
|
||||
|
||||
/*
|
||||
* This is the executive's trap table which is installed into the TBR
|
||||
* register.
|
||||
*
|
||||
* NOTE: Unfortunately, this must be aligned on a 4096 byte boundary.
|
||||
* The GNU tools as of binutils 2.5.2 and gcc 2.7.0 would not
|
||||
* align an entity to anything greater than a 512 byte boundary.
|
||||
*
|
||||
* Because of this, we pull a little bit of a trick. We allocate
|
||||
* enough memory so we can grab an address on a 4096 byte boundary
|
||||
* from this area.
|
||||
*/
|
||||
|
||||
#define SPARC_TRAP_TABLE_ALIGNMENT 4096
|
||||
|
||||
EXTERN unsigned8 _CPU_Trap_Table_area[ 8192 ]
|
||||
__attribute__ ((aligned (SPARC_TRAP_TABLE_ALIGNMENT)));
|
||||
|
||||
|
||||
/*
|
||||
* The size of the floating point context area.
|
||||
*/
|
||||
|
||||
#define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Amount of extra stack (above minimum stack size) required by
|
||||
* system initialization thread. Remember that in a multiprocessor
|
||||
@@ -538,13 +595,43 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
/*
|
||||
* This defines the number of entries in the ISR_Vector_table managed
|
||||
* by the executive.
|
||||
*
|
||||
* On the SPARC, there are really only 256 vectors. However, the executive
|
||||
* has no easy, fast, reliable way to determine which traps are synchronous
|
||||
* and which are asynchronous. By default, synchronous traps return to the
|
||||
* instruction which caused the interrupt. So if you install a software
|
||||
* trap handler as an executive interrupt handler (which is desirable since
|
||||
* RTEMS takes care of window and register issues), then the executive needs
|
||||
* to know that the return address is to the trap rather than the instruction
|
||||
* following the trap.
|
||||
*
|
||||
* So vectors 0 through 255 are treated as regular asynchronous traps which
|
||||
* provide the "correct" return address. Vectors 256 through 512 are assumed
|
||||
* by the executive to be synchronous and to require that the return address
|
||||
* be fudged.
|
||||
*
|
||||
* If you use this mechanism to install a trap handler which must reexecute
|
||||
* the instruction which caused the trap, then it should be installed as
|
||||
* an asynchronous trap. This will avoid the executive changing the return
|
||||
* address.
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 255
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER 511
|
||||
|
||||
#define SPARC_SYNCHRONOUS_TRAP_BIT_MASK 0x100
|
||||
#define SPARC_ASYNCHRONOUS_TRAP( _trap ) (_trap)
|
||||
#define SPARC_SYNCHRONOUS_TRAP( _trap ) ((_trap) + 256 )
|
||||
|
||||
#define SPARC_REAL_TRAP_NUMBER( _trap ) ((_trap) % 256)
|
||||
|
||||
/*
|
||||
* Should be large enough to run all tests. This insures
|
||||
* that a "reasonable" small application should not have any problems.
|
||||
*
|
||||
* This appears to be a fairly generous number for the SPARC since
|
||||
* represents a call depth of about 20 routines based on the minimum
|
||||
* stack frame.
|
||||
*/
|
||||
|
||||
#define CPU_STACK_MINIMUM_SIZE (1024*2)
|
||||
@@ -552,6 +639,8 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
/*
|
||||
* CPU's worst alignment requirement for data types on a byte boundary. This
|
||||
* alignment does not take into account the requirements for the stack.
|
||||
*
|
||||
* On the SPARC, this is required for double word loads and stores.
|
||||
*/
|
||||
|
||||
#define CPU_ALIGNMENT 8
|
||||
@@ -591,12 +680,15 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
* is strict enough for the stack, then this should be set to 0.
|
||||
*
|
||||
* NOTE: This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
|
||||
*
|
||||
* The alignment restrictions for the SPARC are not that strict but this
|
||||
* should unsure that the stack is always sufficiently alignment that the
|
||||
* window overflow, underflow, and flush routines can use double word loads
|
||||
* and stores.
|
||||
*/
|
||||
|
||||
#define CPU_STACK_ALIGNMENT 16
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/* ISR handler macros */
|
||||
@@ -631,12 +723,7 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
/*
|
||||
* Map interrupt level in task mode onto the hardware that the CPU
|
||||
* actually provides. Currently, interrupt levels which do not
|
||||
* map onto the CPU in a generic fashion are undefined. Someday,
|
||||
* it would be nice if these were "mapped" by the application
|
||||
* via a callout. For example, m68k has 8 levels 0 - 7, levels
|
||||
* 8 - 255 would be available for bsp/application specific meaning.
|
||||
* This could be used to manage a programmable interrupt controller
|
||||
* via the rtems_task_mode directive.
|
||||
* map onto the CPU in a straight fashion are undefined.
|
||||
*/
|
||||
|
||||
#define _CPU_ISR_Set_level( _newlevel ) \
|
||||
@@ -659,46 +746,33 @@ unsigned32 _CPU_ISR_Get_level( void );
|
||||
* - setting the proper interrupt level in the context
|
||||
* - initializing the floating point context
|
||||
*
|
||||
* This routine generally does not set any unnecessary register
|
||||
* in the context. The state of the "general data" registers is
|
||||
* undefined at task start time.
|
||||
*
|
||||
* NOTE: Implemented as a subroutine for the SPARC port.
|
||||
*/
|
||||
|
||||
void _CPU_Context_Initialize(
|
||||
Context_Control *_the_context,
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
Context_Control *the_context,
|
||||
unsigned32 *stack_base,
|
||||
unsigned32 size,
|
||||
unsigned32 new_level,
|
||||
void *entry_point,
|
||||
boolean is_fp
|
||||
);
|
||||
|
||||
/*
|
||||
* This routine is responsible for somehow restarting the currently
|
||||
* executing task. If you are lucky, then all that is necessary
|
||||
* is restoring the context. Otherwise, there will need to be
|
||||
* a special assembly routine which does something special in this
|
||||
* case. Context_Restore should work most of the time. It will
|
||||
* not work if restarting self conflicts with the stack frame
|
||||
* assumptions of restoring a context.
|
||||
* executing task.
|
||||
*
|
||||
* On the SPARC, this is is relatively painless but requires a small
|
||||
* amount of wrapper code before using the regular restore code in
|
||||
* of the context switch.
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Restart_self( _the_context ) \
|
||||
_CPU_Context_restore( (_the_context) );
|
||||
|
||||
/*
|
||||
* The purpose of this macro is to allow the initial pointer into
|
||||
* a floating point context area (used to save the floating point
|
||||
* context) to be at an arbitrary place in the floating point
|
||||
* context area.
|
||||
*
|
||||
* This is necessary because some FP units are designed to have
|
||||
* their context saved as a stack which grows into lower addresses.
|
||||
* Other FP units can be saved by simply moving registers into offsets
|
||||
* from the base of the context area. Finally some FP units provide
|
||||
* a "dump context" instruction which could fill in from high to low
|
||||
* or low to high based on the whim of the CPU designers.
|
||||
* The FP context area for the SPARC is a simple structure and nothing
|
||||
* special is required to find the "starting load point"
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Fp_start( _base, _offset ) \
|
||||
@@ -706,20 +780,17 @@ void _CPU_Context_Initialize(
|
||||
|
||||
/*
|
||||
* This routine initializes the FP context area passed to it to.
|
||||
* There are a few standard ways in which to initialize the
|
||||
* floating point context. The code included for this macro assumes
|
||||
* that this is a CPU in which a "initial" FP context was saved into
|
||||
* _CPU_Null_fp_context and it simply copies it to the destination
|
||||
* context passed to it.
|
||||
*
|
||||
* Other models include (1) not doing anything, and (2) putting
|
||||
* a "null FP status word" in the correct place in the FP context.
|
||||
* The SPARC allows us to use the simple initialization model
|
||||
* in which an "initial" FP context was saved into _CPU_Null_fp_context
|
||||
* at CPU initialization and it is simply copied into the destination
|
||||
* context.
|
||||
*/
|
||||
|
||||
#define _CPU_Context_Initialize_fp( _destination ) \
|
||||
{ \
|
||||
do { \
|
||||
*((Context_Control_fp *) *((void **) _destination)) = _CPU_Null_fp_context; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
/* end of Context handler macros */
|
||||
|
||||
@@ -732,122 +803,42 @@ void _CPU_Context_Initialize(
|
||||
*/
|
||||
|
||||
#define _CPU_Fatal_halt( _error ) \
|
||||
{ \
|
||||
}
|
||||
do { \
|
||||
unsigned32 level; \
|
||||
\
|
||||
sparc_disable_interrupts( level ); \
|
||||
asm volatile ( "mov %0, %%g1 " : "=r" (level) : "0" (level) ); \
|
||||
while (1); /* loop forever */ \
|
||||
} while (0)
|
||||
|
||||
/* end of Fatal Error manager macros */
|
||||
|
||||
/* Bitfield handler macros */
|
||||
|
||||
/*
|
||||
* This routine sets _output to the bit number of the first bit
|
||||
* set in _value. _value is of CPU dependent type Priority_Bit_map_control.
|
||||
* This type may be either 16 or 32 bits wide although only the 16
|
||||
* least significant bits will be used.
|
||||
*
|
||||
* There are a number of variables in using a "find first bit" type
|
||||
* instruction.
|
||||
*
|
||||
* (1) What happens when run on a value of zero?
|
||||
* (2) Bits may be numbered from MSB to LSB or vice-versa.
|
||||
* (3) The numbering may be zero or one based.
|
||||
* (4) The "find first bit" instruction may search from MSB or LSB.
|
||||
*
|
||||
* The executive guarantees that (1) will never happen so it is not a concern.
|
||||
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
|
||||
* _CPU_Priority_Bits_index(). These three form a set of routines
|
||||
* which must logically operate together. Bits in the _value are
|
||||
* set and cleared based on masks built by _CPU_Priority_mask().
|
||||
* The basic major and minor values calculated by _Priority_Major()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
|
||||
* to properly range between the values returned by the "find first bit"
|
||||
* instruction. This makes it possible for _Priority_Get_highest() to
|
||||
* calculate the major and directly index into the minor table.
|
||||
* This mapping is necessary to ensure that 0 (a high priority major/minor)
|
||||
* is the first bit found.
|
||||
*
|
||||
* This entire "find first bit" and mapping process depends heavily
|
||||
* on the manner in which a priority is broken into a major and minor
|
||||
* components with the major being the 4 MSB of a priority and minor
|
||||
* the 4 LSB. Thus (0 << 4) + 0 corresponds to priority 0 -- the highest
|
||||
* priority. And (15 << 4) + 14 corresponds to priority 254 -- the next
|
||||
* to the lowest priority.
|
||||
*
|
||||
* If your CPU does not have a "find first bit" instruction, then
|
||||
* there are ways to make do without it. Here are a handful of ways
|
||||
* to implement this in software:
|
||||
*
|
||||
* - a series of 16 bit test instructions
|
||||
* - a "binary search using if's"
|
||||
* - _number = 0
|
||||
* if _value > 0x00ff
|
||||
* _value >>=8
|
||||
* _number = 8;
|
||||
*
|
||||
* if _value > 0x0000f
|
||||
* _value >=8
|
||||
* _number += 4
|
||||
*
|
||||
* _number += bit_set_table[ _value ]
|
||||
*
|
||||
* where bit_set_table[ 16 ] has values which indicate the first
|
||||
* bit set
|
||||
* The SPARC port uses the generic C algorithm for bitfield scan if the
|
||||
* CPU model does not have a scan instruction.
|
||||
*/
|
||||
|
||||
#ifndef INIT
|
||||
extern const unsigned char __log2table[256];
|
||||
#if ( SPARC_HAS_BITSCAN == 0 )
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
|
||||
#else
|
||||
const unsigned char __log2table[256] = {
|
||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
||||
};
|
||||
#error "scan instruction not currently supported by RTEMS!!"
|
||||
#endif
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
{ \
|
||||
register __value = (_value); \
|
||||
\
|
||||
if ( !(__value & 0xff00) ) \
|
||||
(_output) = __log2table[ __value ]; \
|
||||
else \
|
||||
(_output) = __log2table[ __value >> 8 ] + 8; \
|
||||
}
|
||||
|
||||
|
||||
/* end of Bitfield handler macros */
|
||||
|
||||
/*
|
||||
* This routine builds the mask which corresponds to the bit fields
|
||||
* as searched by _CPU_Bitfield_Find_first_bit(). See the discussion
|
||||
* for that routine.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 0x8000 >> (_bit_number) )
|
||||
/* Priority handler handler macros */
|
||||
|
||||
/*
|
||||
* This routine translates the bit numbers returned by
|
||||
* _CPU_Bitfield_Find_first_bit() into something suitable for use as
|
||||
* a major or minor component of a priority. See the discussion
|
||||
* for that routine.
|
||||
* The SPARC port uses the generic C algorithm for bitfield scan if the
|
||||
* CPU model does not have a scan instruction.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
(15 - (_priority))
|
||||
#if ( SPARC_HAS_BITSCAN == 1 )
|
||||
#error "scan instruction not currently supported by RTEMS!!"
|
||||
#endif
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
@@ -864,6 +855,19 @@ void _CPU_Initialize(
|
||||
void (*thread_dispatch)
|
||||
);
|
||||
|
||||
/*
|
||||
* _CPU_ISR_install_raw_handler
|
||||
*
|
||||
* This routine installs new_handler to be directly called from the trap
|
||||
* table.
|
||||
*/
|
||||
|
||||
void _CPU_ISR_install_raw_handler(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
);
|
||||
|
||||
/*
|
||||
* _CPU_ISR_install_vector
|
||||
*
|
||||
@@ -876,28 +880,19 @@ void _CPU_ISR_install_vector(
|
||||
proc_ptr *old_handler
|
||||
);
|
||||
|
||||
/*
|
||||
* _CPU_Install_interrupt_stack
|
||||
*
|
||||
* This routine installs the hardware interrupt stack pointer.
|
||||
*
|
||||
* NOTE: It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK
|
||||
* is TRUE.
|
||||
*/
|
||||
|
||||
void _CPU_Install_interrupt_stack( void );
|
||||
#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
|
||||
|
||||
/*
|
||||
* _CPU_Internal_threads_Idle_thread_body
|
||||
*
|
||||
* This routine is the CPU dependent IDLE thread body.
|
||||
*
|
||||
* NOTE: It need only be provided if CPU_PROVIDES_IDLE_THREAD_BODY
|
||||
* is TRUE.
|
||||
* Some SPARC implementations have low power, sleep, or idle modes. This
|
||||
* tries to take advantage of those models.
|
||||
*/
|
||||
|
||||
void _CPU_Internal_threads_Idle_thread_body( void );
|
||||
|
||||
#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
|
||||
|
||||
/*
|
||||
* _CPU_Context_switch
|
||||
*
|
||||
@@ -913,9 +908,7 @@ void _CPU_Context_switch(
|
||||
* _CPU_Context_restore
|
||||
*
|
||||
* This routine is generallu 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.
|
||||
* efficient manner.
|
||||
*/
|
||||
|
||||
void _CPU_Context_restore(
|
||||
@@ -942,24 +935,23 @@ void _CPU_Context_restore_fp(
|
||||
void **fp_context_ptr
|
||||
);
|
||||
|
||||
/* The following routine swaps the endian format of an unsigned int.
|
||||
/*
|
||||
* CPU_swap_u32
|
||||
*
|
||||
* The following routine swaps the endian format of an unsigned int.
|
||||
* It must be static because it is referenced indirectly.
|
||||
*
|
||||
* This version will work on any processor, but if there is a better
|
||||
* way for your CPU PLEASE use it. The most common way to do this is to:
|
||||
* This version will work on any processor, but if you come across a better
|
||||
* way for the SPARC PLEASE use it. The most common way to swap a 32-bit
|
||||
* entity as shown below is not any more efficient on the SPARC.
|
||||
*
|
||||
* swap least significant two bytes with 16-bit rotate
|
||||
* swap upper and lower 16-bits
|
||||
* swap most significant two bytes with 16-bit rotate
|
||||
*
|
||||
* Some CPUs have special instructions which swap a 32-bit quantity in
|
||||
* a single instruction (e.g. i486). It is probably best to avoid
|
||||
* an "endian swapping control bit" in the CPU. One good reason is
|
||||
* that interrupts would probably have to be disabled to insure that
|
||||
* an interrupt does not try to access the same "chunk" with the wrong
|
||||
* endian. Another good reason is that on some CPUs, the endian bit
|
||||
* endianness for ALL fetches -- both code and data -- so the code
|
||||
* will be fetched incorrectly.
|
||||
* It is not obvious how the SPARC can do significantly better than the
|
||||
* generic code. gcc 2.7.0 only generates about 12 instructions for the
|
||||
* following code at optimization level four (i.e. -O4).
|
||||
*/
|
||||
|
||||
static inline unsigned int CPU_swap_u32(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* 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
|
||||
* in assembly language.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
@@ -10,319 +10,680 @@
|
||||
#include <asm.h>
|
||||
#include <rtems/score/cpu.h>
|
||||
|
||||
#if (SPARC_HAS_FPU == 1)
|
||||
|
||||
/*
|
||||
* _CPU_Context_save_fp
|
||||
* void _CPU_Context_save_fp(
|
||||
* void **fp_context_ptr
|
||||
* )
|
||||
*
|
||||
* 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
|
||||
* )
|
||||
* {
|
||||
* }
|
||||
* NOTE: See the README in this directory for information on the
|
||||
* management of the "EF" bit in the PSR.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
PUBLIC(_CPU_Context_save_fp)
|
||||
SYM(_CPU_Context_save_fp):
|
||||
save %sp,-104,%sp
|
||||
ld [%i0],%l0
|
||||
std %f0,[%l0+FO_F1_OFFSET]
|
||||
std %f2,[%l0+F2_F3_OFFSET]
|
||||
std %f4,[%l0+F4_F5_OFFSET]
|
||||
std %f6,[%l0+F6_F7_OFFSET]
|
||||
std %f8,[%l0+F8_F9_OFFSET]
|
||||
std %f10,[%l0+F1O_F11_OFFSET]
|
||||
std %f12,[%l0+F12_F13_OFFSET]
|
||||
std %f14,[%l0+F14_F15_OFFSET]
|
||||
std %f16,[%l0+F16_F17_OFFSET]
|
||||
std %f18,[%l0+F18_F19_OFFSET]
|
||||
std %f20,[%l0+F2O_F21_OFFSET]
|
||||
std %f22,[%l0+F22_F23_OFFSET]
|
||||
std %f24,[%l0+F24_F25_OFFSET]
|
||||
std %f26,[%l0+F26_F27_OFFSET]
|
||||
std %f28,[%l0+F28_F29_OFFSET]
|
||||
std %f30,[%l0+F3O_F31_OFFSET]
|
||||
st %fsr,[%l0+FSR_OFFSET]
|
||||
save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
|
||||
|
||||
/*
|
||||
* The following enables the floating point unit.
|
||||
*/
|
||||
|
||||
mov %psr, %l0
|
||||
sethi %hi(SPARC_PSR_EF_MASK), %l1
|
||||
or %l1, %lo(SPARC_PSR_EF_MASK), %l1
|
||||
or %l0, %l1, %l0
|
||||
mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
|
||||
|
||||
ld [%i0], %l0
|
||||
std %f0, [%l0 + FO_F1_OFFSET]
|
||||
std %f2, [%l0 + F2_F3_OFFSET]
|
||||
std %f4, [%l0 + F4_F5_OFFSET]
|
||||
std %f6, [%l0 + F6_F7_OFFSET]
|
||||
std %f8, [%l0 + F8_F9_OFFSET]
|
||||
std %f10, [%l0 + F1O_F11_OFFSET]
|
||||
std %f12, [%l0 + F12_F13_OFFSET]
|
||||
std %f14, [%l0 + F14_F15_OFFSET]
|
||||
std %f16, [%l0 + F16_F17_OFFSET]
|
||||
std %f18, [%l0 + F18_F19_OFFSET]
|
||||
std %f20, [%l0 + F2O_F21_OFFSET]
|
||||
std %f22, [%l0 + F22_F23_OFFSET]
|
||||
std %f24, [%l0 + F24_F25_OFFSET]
|
||||
std %f26, [%l0 + F26_F27_OFFSET]
|
||||
std %f28, [%l0 + F28_F29_OFFSET]
|
||||
std %f30, [%l0 + F3O_F31_OFFSET]
|
||||
st %fsr, [%l0 + FSR_OFFSET]
|
||||
ret
|
||||
restore
|
||||
|
||||
/*
|
||||
* _CPU_Context_restore_fp
|
||||
* void _CPU_Context_restore_fp(
|
||||
* void **fp_context_ptr
|
||||
* )
|
||||
*
|
||||
* 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
|
||||
* )
|
||||
* {
|
||||
* }
|
||||
* NOTE: See the README in this directory for information on the
|
||||
* management of the "EF" bit in the PSR.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
PUBLIC(_CPU_Context_restore_fp)
|
||||
SYM(_CPU_Context_restore_fp):
|
||||
save %sp,-104,%sp
|
||||
ld [%o0],%l0
|
||||
ldd [%l0+FO_F1_OFFSET],%f0
|
||||
ldd [%l0+F2_F3_OFFSET],%f2
|
||||
ldd [%l0+F4_F5_OFFSET],%f4
|
||||
ldd [%l0+F6_F7_OFFSET],%f6
|
||||
ldd [%l0+F8_F9_OFFSET],%f8
|
||||
ldd [%l0+F1O_F11_OFFSET],%f10
|
||||
ldd [%l0+F12_F13_OFFSET],%f12
|
||||
ldd [%l0+F14_F15_OFFSET],%f14
|
||||
ldd [%l0+F16_F17_OFFSET],%f16
|
||||
ldd [%l0+F18_F19_OFFSET],%f18
|
||||
ldd [%l0+F2O_F21_OFFSET],%f20
|
||||
ldd [%l0+F22_F23_OFFSET],%f22
|
||||
ldd [%l0+F24_F25_OFFSET],%f24
|
||||
ldd [%l0+F26_F27_OFFSET],%f26
|
||||
ldd [%l0+F28_F29_OFFSET],%f28
|
||||
ldd [%l0+F3O_F31_OFFSET],%f30
|
||||
ld [%l0+FSR_OFFSET],%fsr
|
||||
save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE , %sp
|
||||
|
||||
/*
|
||||
* The following enables the floating point unit.
|
||||
*/
|
||||
|
||||
mov %psr, %l0
|
||||
sethi %hi(SPARC_PSR_EF_MASK), %l1
|
||||
or %l1, %lo(SPARC_PSR_EF_MASK), %l1
|
||||
or %l0, %l1, %l0
|
||||
mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
|
||||
|
||||
ld [%i0], %l0
|
||||
ldd [%l0 + FO_F1_OFFSET], %f0
|
||||
ldd [%l0 + F2_F3_OFFSET], %f2
|
||||
ldd [%l0 + F4_F5_OFFSET], %f4
|
||||
ldd [%l0 + F6_F7_OFFSET], %f6
|
||||
ldd [%l0 + F8_F9_OFFSET], %f8
|
||||
ldd [%l0 + F1O_F11_OFFSET], %f10
|
||||
ldd [%l0 + F12_F13_OFFSET], %f12
|
||||
ldd [%l0 + F14_F15_OFFSET], %f14
|
||||
ldd [%l0 + F16_F17_OFFSET], %f16
|
||||
ldd [%l0 + F18_F19_OFFSET], %f18
|
||||
ldd [%l0 + F2O_F21_OFFSET], %f20
|
||||
ldd [%l0 + F22_F23_OFFSET], %f22
|
||||
ldd [%l0 + F24_F25_OFFSET], %f24
|
||||
ldd [%l0 + F26_F27_OFFSET], %f26
|
||||
ldd [%l0 + F28_F29_OFFSET], %f28
|
||||
ldd [%l0 + F3O_F31_OFFSET], %f30
|
||||
ld [%l0 + FSR_OFFSET], %fsr
|
||||
ret
|
||||
restore
|
||||
|
||||
/* _CPU_Context_switch
|
||||
*
|
||||
* This routine performs a normal non-FP context switch.
|
||||
*
|
||||
#endif /* SPARC_HAS_FPU */
|
||||
|
||||
/*
|
||||
* void _CPU_Context_switch(
|
||||
* Context_Control *run,
|
||||
* Context_Control *heir
|
||||
* )
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* This routine performs a normal non-FP context switch.
|
||||
*/
|
||||
|
||||
/* from gcc-2.7.0/config/sparc/sparc.h on register usage */
|
||||
|
||||
/* 1 for registers that have pervasive standard uses
|
||||
and are not available for the register allocator.
|
||||
g0 is used for the condition code and not to represent %g0, which is
|
||||
hardwired to 0, so reg 0 is *not* fixed.
|
||||
On non-v9 systems:
|
||||
g1 is free to use as temporary.
|
||||
g2-g4 are reserved for applications. Gcc normally uses them as
|
||||
temporaries, but this can be disabled via the -mno-app-regs option.
|
||||
g5 through g7 are reserved for the operating system.
|
||||
On v9 systems:
|
||||
g1 and g5 are free to use as temporaries.
|
||||
g2-g4 are reserved for applications (the compiler will not normally use
|
||||
them, but they can be used as temporaries with -mapp-regs).
|
||||
g6-g7 are reserved for the operating system.
|
||||
??? Register 1 is used as a temporary by the 64 bit sethi pattern, so must
|
||||
currently be a fixed register until this pattern is rewritten.
|
||||
Register 1 is also used when restoring call-preserved registers in large
|
||||
stack frames. */
|
||||
|
||||
|
||||
.align 4
|
||||
PUBLIC(_CPU_Context_switch)
|
||||
SYM(_CPU_Context_switch):
|
||||
ta 0x03 /* flush registers */
|
||||
! skip g0
|
||||
st %g1, [%o0 + G1_OFFSET] ! save the global registers
|
||||
std %g2, [%o0 + G2_OFFSET]
|
||||
std %g4, [%o0 + G4_OFFSET]
|
||||
std %g6, [%o0 + G6_OFFSET]
|
||||
|
||||
/* skip g0 */
|
||||
st %g1,[%o0+G1_OFFSET] /* globals */
|
||||
st %g2,[%o0+G2_OFFSET]
|
||||
st %g3,[%o0+G3_OFFSET]
|
||||
st %g4,[%o0+G4_OFFSET]
|
||||
st %g5,[%o0+G5_OFFSET]
|
||||
st %g6,[%o0+G6_OFFSET]
|
||||
st %g7,[%o0+G7_OFFSET]
|
||||
std %l0, [%o0 + L0_OFFSET] ! save the local registers
|
||||
std %l2, [%o0 + L2_OFFSET]
|
||||
std %l4, [%o0 + L4_OFFSET]
|
||||
std %l6, [%o0 + L6_OFFSET]
|
||||
|
||||
st %l0,[%o0+L0_OFFSET]
|
||||
st %l1,[%o0+L1_OFFSET]
|
||||
st %l2,[%o0+L2_OFFSET]
|
||||
st %l3,[%o0+L3_OFFSET]
|
||||
st %l4,[%o0+L4_OFFSET]
|
||||
st %l5,[%o0+L5_OFFSET]
|
||||
st %l6,[%o0+L6_OFFSET]
|
||||
st %l7,[%o0+L7_OFFSET]
|
||||
std %i0, [%o0 + I0_OFFSET] ! save the input registers
|
||||
std %i2, [%o0 + I2_OFFSET]
|
||||
std %i4, [%o0 + I4_OFFSET]
|
||||
std %i6, [%o0 + I6_FP_OFFSET]
|
||||
|
||||
st %i0,[%o0+I0_OFFSET]
|
||||
st %i1,[%o0+I1_OFFSET]
|
||||
st %i2,[%o0+I2_OFFSET]
|
||||
st %i3,[%o0+I3_OFFSET]
|
||||
st %i4,[%o0+I4_OFFSET]
|
||||
st %i5,[%o0+I5_OFFSET]
|
||||
st %i6,[%o0+I6_OFFSET]
|
||||
st %i7,[%o0+I7_OFFSET]
|
||||
std %o0, [%o0 + O0_OFFSET] ! save the output registers
|
||||
std %o2, [%o0 + O2_OFFSET]
|
||||
std %o4, [%o0 + O4_OFFSET]
|
||||
std %o6, [%o0 + O6_SP_OFFSET]
|
||||
|
||||
st %o0,[%o0+O0_OFFSET]
|
||||
st %o1,[%o0+O1_OFFSET]
|
||||
st %o2,[%o0+O2_OFFSET]
|
||||
st %o3,[%o0+O3_OFFSET]
|
||||
st %o4,[%o0+O4_OFFSET]
|
||||
st %o5,[%o0+O5_OFFSET]
|
||||
st %o6,[%o0+O6_OFFSET]
|
||||
st %o7,[%o0+O7_OFFSET]
|
||||
rd %psr, %o2
|
||||
st %o2, [%o0 + PSR_OFFSET] ! save status register
|
||||
|
||||
rd %psr,%o2
|
||||
st %o2,[%o0+PSR_OFFSET] /* save status register */
|
||||
/*
|
||||
* This is entered from _CPU_Context_restore with:
|
||||
* o1 = context to restore
|
||||
* o2 = psr
|
||||
*/
|
||||
|
||||
/* enter here with o1 = context to restore */
|
||||
/* o2 = psr */
|
||||
restore:
|
||||
PUBLIC(_CPU_Context_restore_heir)
|
||||
SYM(_CPU_Context_restore_heir):
|
||||
/*
|
||||
* Flush all windows with valid contents except the current one.
|
||||
* In examining the set register windows, one may logically divide
|
||||
* the windows into sets (some of which may be empty) based on their
|
||||
* current status:
|
||||
*
|
||||
* + current (i.e. in use),
|
||||
* + used (i.e. a restore would not trap)
|
||||
* + invalid (i.e. 1 in corresponding bit in WIM)
|
||||
* + unused
|
||||
*
|
||||
* Either the used or unused set of windows may be empty.
|
||||
*
|
||||
* NOTE: We assume only one bit is set in the WIM at a time.
|
||||
*
|
||||
* Given a CWP of 5 and a WIM of 0x1, the registers are divided
|
||||
* into sets as follows:
|
||||
*
|
||||
* + 0 - invalid
|
||||
* + 1-4 - unused
|
||||
* + 5 - current
|
||||
* + 6-7 - used
|
||||
*
|
||||
* In this case, we only would save the used windows -- 6 and 7.
|
||||
*
|
||||
* Traps are disabled for the same logical period as in a
|
||||
* flush all windows trap handler.
|
||||
*
|
||||
* Register Usage while saving the windows:
|
||||
* g1 = current PSR
|
||||
* g2 = current wim
|
||||
* g3 = CWP
|
||||
* g4 = wim scratch
|
||||
* g5 = scratch
|
||||
*/
|
||||
|
||||
ld [%o1+PSR_OFFSET],%o0
|
||||
and %o2,31,%o2 /* g1 = cwp */
|
||||
and %o0,-32,%o0 /* o0 = psr w/o cwp */
|
||||
or %o0,%o2,%o2 /* o2 = new psr */
|
||||
wr %o2,0,%psr /* restore status register */
|
||||
ld [%o1 + PSR_OFFSET], %g1 ! g1 = saved psr
|
||||
|
||||
/* skip g0 */
|
||||
ld [%o1+G1_OFFSET],%g1
|
||||
ld [%o1+G2_OFFSET],%g2
|
||||
ld [%o1+G3_OFFSET],%g3
|
||||
ld [%o1+G4_OFFSET],%g4
|
||||
ld [%o1+G5_OFFSET],%g5
|
||||
ld [%o1+G6_OFFSET],%g6
|
||||
ld [%o1+G7_OFFSET],%g7
|
||||
and %o2, SPARC_PSR_CWP_MASK, %g3 ! g3 = CWP
|
||||
! g1 = psr w/o cwp
|
||||
andn %g1, SPARC_PSR_ET_MASK | SPARC_PSR_CWP_MASK, %g1
|
||||
or %g1, %g3, %g1 ! g1 = heirs psr
|
||||
mov %g1, %psr ! restore status register and
|
||||
! **** DISABLE TRAPS ****
|
||||
mov %wim, %g2 ! g2 = wim
|
||||
mov 1, %g4
|
||||
sll %g4, %g3, %g4 ! g4 = WIM mask for CW invalid
|
||||
|
||||
ld [%o1+L0_OFFSET],%l0
|
||||
ld [%o1+L1_OFFSET],%l1
|
||||
ld [%o1+L2_OFFSET],%l2
|
||||
ld [%o1+L3_OFFSET],%l3
|
||||
ld [%o1+L4_OFFSET],%l4
|
||||
ld [%o1+L5_OFFSET],%l5
|
||||
ld [%o1+L6_OFFSET],%l6
|
||||
ld [%o1+L7_OFFSET],%l7
|
||||
save_frame_loop:
|
||||
sll %g4, 1, %g5 ! rotate the "wim" left 1
|
||||
srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
|
||||
or %g4, %g5, %g4 ! g4 = wim if we do one restore
|
||||
|
||||
ld [%o1+I0_OFFSET],%i0
|
||||
ld [%o1+I1_OFFSET],%i1
|
||||
ld [%o1+I2_OFFSET],%i2
|
||||
ld [%o1+I3_OFFSET],%i3
|
||||
ld [%o1+I4_OFFSET],%i4
|
||||
ld [%o1+I5_OFFSET],%i5
|
||||
ld [%o1+I6_OFFSET],%i6
|
||||
ld [%o1+I7_OFFSET],%i7
|
||||
/*
|
||||
* If a restore would not underflow, then continue.
|
||||
*/
|
||||
|
||||
ld [%o1+O0_OFFSET],%o0
|
||||
/* do o1 last to avoid destroying heir context pointer */
|
||||
ld [%o1+O2_OFFSET],%o2
|
||||
ld [%o1+O3_OFFSET],%o3
|
||||
ld [%o1+O4_OFFSET],%o4
|
||||
ld [%o1+O5_OFFSET],%o5
|
||||
ld [%o1+O6_OFFSET],%o6
|
||||
ld [%o1+O7_OFFSET],%o7
|
||||
andcc %g4, %g2, %g0 ! Any windows to flush?
|
||||
bnz done_flushing ! No, then continue
|
||||
nop
|
||||
|
||||
ld [%o1+O1_OFFSET],%o1 /* overwrite heir pointer */
|
||||
restore ! back one window
|
||||
|
||||
jmp %o7 + 8 /* return */
|
||||
nop /* delay slot */
|
||||
/*
|
||||
* Now save the window just as if we overflowed to it.
|
||||
*/
|
||||
|
||||
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
||||
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
||||
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
||||
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
||||
|
||||
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
||||
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
||||
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
||||
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
||||
|
||||
ba save_frame_loop
|
||||
nop
|
||||
|
||||
done_flushing:
|
||||
|
||||
add %g3, 1, %g3 ! calculate desired WIM
|
||||
and %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
|
||||
mov 1, %g4
|
||||
sll %g4, %g3, %g4 ! g4 = new WIM
|
||||
mov %g4, %wim
|
||||
|
||||
or %g1, SPARC_PSR_ET_MASK, %g1
|
||||
mov %g1, %psr ! **** ENABLE TRAPS ****
|
||||
! and restore CWP
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
! skip g0
|
||||
ld [%o1 + G1_OFFSET], %g1 ! restore the global registers
|
||||
ldd [%o1 + G2_OFFSET], %g2
|
||||
ldd [%o1 + G4_OFFSET], %g4
|
||||
ldd [%o1 + G6_OFFSET], %g6
|
||||
|
||||
ldd [%o1 + L0_OFFSET], %l0 ! restore the local registers
|
||||
ldd [%o1 + L2_OFFSET], %l2
|
||||
ldd [%o1 + L4_OFFSET], %l4
|
||||
ldd [%o1 + L6_OFFSET], %l6
|
||||
|
||||
ldd [%o1 + I0_OFFSET], %i0 ! restore the output registers
|
||||
ldd [%o1 + I2_OFFSET], %i2
|
||||
ldd [%o1 + I4_OFFSET], %i4
|
||||
ldd [%o1 + I6_FP_OFFSET], %i6
|
||||
|
||||
ldd [%o1 + O2_OFFSET], %o2 ! restore the output registers
|
||||
ldd [%o1 + O4_OFFSET], %o4
|
||||
ldd [%o1 + O6_SP_OFFSET], %o6
|
||||
! do o0/o1 last to avoid destroying heir context pointer
|
||||
ldd [%o1 + O0_OFFSET], %o0 ! overwrite heir pointer
|
||||
|
||||
jmp %o7 + 8 ! return
|
||||
nop ! delay slot
|
||||
|
||||
/*
|
||||
* _CPU_Context_restore
|
||||
*
|
||||
* This routine is generallu 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.
|
||||
*
|
||||
* void _CPU_Context_restore(
|
||||
* Context_Control *new_context
|
||||
* )
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* This routine is generally used only to perform restart self.
|
||||
*
|
||||
* NOTE: It is unnecessary to reload some registers.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
PUBLIC(_CPU_Context_restore)
|
||||
SYM(_CPU_Context_restore):
|
||||
save %sp, -104, %sp /* save a stack frame */
|
||||
ta 0x03 /* flush registers */
|
||||
rd %psr,%o2
|
||||
ba restore
|
||||
mov %i0,%o1 /* in the delay slot */
|
||||
save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
|
||||
rd %psr, %o2
|
||||
ba SYM(_CPU_Context_restore_heir)
|
||||
mov %i0, %o1 ! in the delay slot
|
||||
|
||||
/* void _ISR_Handler()
|
||||
/*
|
||||
* void _ISR_Handler()
|
||||
*
|
||||
* This routine provides the RTEMS interrupt management.
|
||||
*
|
||||
* void _ISR_Handler()
|
||||
* {
|
||||
* }
|
||||
* We enter this handler from the 4 instructions in the trap table with
|
||||
* the following registers assumed to be set as shown:
|
||||
*
|
||||
* l0 = PSR
|
||||
* l1 = PC
|
||||
* l2 = nPC
|
||||
* l3 = trap type
|
||||
*
|
||||
* NOTE: By an executive defined convention, trap type is between 0 and 255 if
|
||||
* it is an asynchonous trap and 256 and 511 if it is synchronous.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
PUBLIC(_ISR_Handler)
|
||||
SYM(_ISR_Handler):
|
||||
ret
|
||||
/*
|
||||
* Fix the return address for synchronous traps.
|
||||
*/
|
||||
|
||||
andcc %l3, SPARC_SYNCHRONOUS_TRAP_BIT_MASK, %g0
|
||||
! Is this a synchronous trap?
|
||||
be,a win_ovflow ! No, then skip the adjustment
|
||||
nop ! DELAY
|
||||
mov %l2, %l1 ! do not return to the instruction
|
||||
add %l2, 4, %l2 ! indicated
|
||||
|
||||
win_ovflow:
|
||||
/*
|
||||
* Save the globals this block uses.
|
||||
*
|
||||
* These registers are not restored from the locals. Their contents
|
||||
* are saved directly from the locals into the ISF below.
|
||||
*/
|
||||
|
||||
mov %g4, %l4 ! save the globals this block uses
|
||||
mov %g5, %l5
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* When at a "window overflow" trap, (wim == (1 << cwp)).
|
||||
* If we get here like that, then process a window overflow.
|
||||
*/
|
||||
|
||||
rd %wim, %g4
|
||||
srl %g4, %l0, %g5 ! g5 = win >> cwp ; shift count and CWP
|
||||
! are LS 5 bits ; how convenient :)
|
||||
cmp %g5, 1 ! Is this an invalid window?
|
||||
bne dont_do_the_window ! No, then skip all this stuff
|
||||
! we are using the delay slot
|
||||
|
||||
/*
|
||||
* The following is same as a 1 position right rotate of WIM
|
||||
*/
|
||||
|
||||
srl %g4, 1, %g5 ! g5 = WIM >> 1
|
||||
sll %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4
|
||||
! g4 = WIM << (Number Windows - 1)
|
||||
or %g4, %g5, %g4 ! g4 = (WIM >> 1) |
|
||||
! (WIM << (Number Windows - 1))
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
*
|
||||
* 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
|
||||
* g4 = the new WIM
|
||||
* g5 is free
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* _ISR_Nest_level++;
|
||||
*
|
||||
* _Thread_Dispatch_disable_level++;
|
||||
*
|
||||
* (*_ISR_Vector_table[ vector ])( vector );
|
||||
*
|
||||
* --_ISR_Nest_level;
|
||||
*
|
||||
* if ( _ISR_Nest_level )
|
||||
* goto the label "exit interrupt (simple case)"
|
||||
*
|
||||
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
|
||||
* restore stack
|
||||
* #endif
|
||||
*
|
||||
* if ( !_Context_Switch_necessary )
|
||||
* goto the label "exit interrupt (simple case)"
|
||||
*
|
||||
* if ( !_ISR_Signals_to_thread_executing )
|
||||
* goto the label "exit interrupt (simple case)"
|
||||
*
|
||||
* call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
|
||||
*
|
||||
* 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
|
||||
* Since we are tinkering with the register windows, we need to
|
||||
* make sure that all the required information is in global registers.
|
||||
*/
|
||||
|
||||
save ! Save into the window
|
||||
wr %g4, 0, %wim ! WIM = new WIM
|
||||
nop ! delay slots
|
||||
nop
|
||||
nop
|
||||
|
||||
/*
|
||||
* Now save the window just as if we overflowed to it.
|
||||
*/
|
||||
|
||||
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
||||
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
||||
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
||||
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
||||
|
||||
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
||||
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
||||
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
||||
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
||||
|
||||
restore
|
||||
nop
|
||||
|
||||
dont_do_the_window:
|
||||
/*
|
||||
* Global registers %g4 and %g5 are saved directly from %l4 and
|
||||
* %l5 directly into the ISF below.
|
||||
*/
|
||||
|
||||
save_isf:
|
||||
|
||||
/*
|
||||
* Save the state of the interrupted task -- especially the global
|
||||
* registers -- in the Interrupt Stack Frame. Note that the ISF
|
||||
* includes a regular minimum stack frame which will be used if
|
||||
* needed by register window overflow and underflow handlers.
|
||||
*
|
||||
* REGISTERS SAME AS AT _ISR_Handler
|
||||
*/
|
||||
|
||||
sub %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
|
||||
! make space for ISF
|
||||
|
||||
std %l0, [%sp + ISF_PSR_OFFSET] ! save psr, PC
|
||||
st %l2, [%sp + ISF_NPC_OFFSET] ! save nPC
|
||||
st %g1, [%sp + ISF_G1_OFFSET] ! save g1
|
||||
std %g2, [%sp + ISF_G2_OFFSET] ! save g2, g3
|
||||
std %l4, [%sp + ISF_G4_OFFSET] ! save g4, g5 -- see above
|
||||
std %g6, [%sp + ISF_G6_OFFSET] ! save g6, g7
|
||||
|
||||
std %i0, [%sp + ISF_I0_OFFSET] ! save i0, i1
|
||||
std %i2, [%sp + ISF_I2_OFFSET] ! save i2, i3
|
||||
std %i4, [%sp + ISF_I4_OFFSET] ! save i4, i5
|
||||
std %i6, [%sp + ISF_I6_FP_OFFSET] ! save i6/fp, i7
|
||||
|
||||
rd %y, %g1
|
||||
st %g1, [%sp + ISF_Y_OFFSET] ! save y
|
||||
|
||||
mov %sp, %o1 ! 2nd arg to ISR Handler
|
||||
|
||||
/*
|
||||
* Increment ISR nest level and Thread dispatch disable level.
|
||||
*
|
||||
* Register usage for this section:
|
||||
*
|
||||
* l4 = _Thread_Dispatch_disable_level pointer
|
||||
* l5 = _ISR_Nest_level pointer
|
||||
* l6 = _Thread_Dispatch_disable_level value
|
||||
* l7 = _ISR_Nest_level value
|
||||
*
|
||||
* NOTE: It is assumed that l4 - l7 will be preserved until the ISR
|
||||
* nest and thread dispatch disable levels are unnested.
|
||||
*/
|
||||
|
||||
sethi %hi(SYM(_Thread_Dispatch_disable_level)), %l4
|
||||
ld [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))], %l6
|
||||
sethi %hi(SYM(_ISR_Nest_level)), %l5
|
||||
ld [%l5 + %lo(SYM(_ISR_Nest_level))], %l7
|
||||
|
||||
add %l6, 1, %l6
|
||||
st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
|
||||
|
||||
add %l7, 1, %l7
|
||||
st %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
|
||||
|
||||
/*
|
||||
* If ISR nest level was zero (now 1), then switch stack.
|
||||
*/
|
||||
|
||||
mov %sp, %fp
|
||||
subcc %l7, 1, %l7 ! outermost interrupt handler?
|
||||
bnz dont_switch_stacks ! No, then do not switch stacks
|
||||
|
||||
sethi %hi(SYM(_CPU_Interrupt_stack_high)), %g4
|
||||
ld [%g4 + %lo(SYM(_CPU_Interrupt_stack_high))], %sp
|
||||
|
||||
dont_switch_stacks:
|
||||
/*
|
||||
* Make sure we have a place on the stack for the window overflow
|
||||
* trap handler to write into. At this point it is safe to
|
||||
* enable traps again.
|
||||
*/
|
||||
|
||||
sub %sp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
|
||||
|
||||
wr %l0, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
|
||||
|
||||
/*
|
||||
* Vector to user's handler.
|
||||
*
|
||||
* NOTE: TBR may no longer have vector number in it since
|
||||
* we just enabled traps. It is definitely in l3.
|
||||
*/
|
||||
|
||||
sethi %hi(SYM(_ISR_Vector_table)), %g4
|
||||
or %g4, %lo(SYM(_ISR_Vector_table)), %g4
|
||||
and %l3, 0xFF, %g5 ! remove synchronous trap indicator
|
||||
sll %g5, 2, %g5 ! g5 = offset into table
|
||||
ld [%g4 + %g5], %g4 ! g4 = _ISR_Vector_table[ vector ]
|
||||
|
||||
|
||||
! o1 = 2nd arg = address of the ISF
|
||||
! WAS LOADED WHEN ISF WAS SAVED!!!
|
||||
mov %l3, %o0 ! o0 = 1st arg = vector number
|
||||
call %g4, 0
|
||||
nop ! delay slot
|
||||
|
||||
/*
|
||||
* Redisable traps so we can finish up the interrupt processing.
|
||||
* This is a VERY conservative place to do this.
|
||||
*
|
||||
* NOTE: %l0 has the PSR which was in place when we took the trap.
|
||||
*/
|
||||
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
|
||||
/*
|
||||
* Decrement ISR nest level and Thread dispatch disable level.
|
||||
*
|
||||
* Register usage for this section:
|
||||
*
|
||||
* l4 = _Thread_Dispatch_disable_level pointer
|
||||
* l5 = _ISR_Nest_level pointer
|
||||
* l6 = _Thread_Dispatch_disable_level value
|
||||
* l7 = _ISR_Nest_level value
|
||||
*/
|
||||
|
||||
sub %l6, 1, %l6
|
||||
st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
|
||||
|
||||
st %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
|
||||
|
||||
/*
|
||||
* If dispatching is disabled (includes nested interrupt case),
|
||||
* then do a "simple" exit.
|
||||
*/
|
||||
|
||||
orcc %l6, %g0, %g0 ! Is dispatching disabled?
|
||||
bnz simple_return ! Yes, then do a "simple" exit
|
||||
nop ! delay slot
|
||||
|
||||
/*
|
||||
* If a context switch is necessary, then do fudge stack to
|
||||
* return to the interrupt dispatcher.
|
||||
*/
|
||||
|
||||
sethi %hi(SYM(_Context_Switch_necessary)), %l4
|
||||
ld [%l4 + %lo(SYM(_Context_Switch_necessary))], %l5
|
||||
|
||||
orcc %l5, %g0, %g0 ! Is thread switch necessary?
|
||||
bnz SYM(_ISR_Dispatch) ! yes, then invoke the dispatcher
|
||||
nop ! delay slot
|
||||
|
||||
/*
|
||||
* Finally, check to see if signals were sent to the currently
|
||||
* executing task. If so, we need to invoke the interrupt dispatcher.
|
||||
*/
|
||||
|
||||
sethi %hi(SYM(_ISR_Signals_to_thread_executing)), %l6
|
||||
ld [%l6 + %lo(SYM(_ISR_Signals_to_thread_executing))], %l7
|
||||
|
||||
orcc %l7, %g0, %g0 ! Were signals sent to the currently
|
||||
! executing thread?
|
||||
bz simple_return ! yes, then invoke the dispatcher
|
||||
nop ! delay slot
|
||||
|
||||
/*
|
||||
* Invoke interrupt dispatcher.
|
||||
*/
|
||||
|
||||
PUBLIC(_ISR_Dispatch)
|
||||
SYM(_ISR_Dispatch):
|
||||
|
||||
/*
|
||||
* The following subtract should get us back on the interrupted
|
||||
* tasks stack and add enough room to invoke the dispatcher.
|
||||
* When we enable traps, we are mostly back in the context
|
||||
* of the task and subsequent interrupts can operate normally.
|
||||
*/
|
||||
|
||||
sub %fp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
|
||||
|
||||
or %l0, SPARC_PSR_ET_MASK, %l7 ! l7 = PSR with ET=1
|
||||
mov %l7, %psr ! **** ENABLE TRAPS ****
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
call SYM(_Thread_Dispatch), 0
|
||||
nop
|
||||
|
||||
/*
|
||||
* The CWP in place at this point may be different from
|
||||
* that which was in effect at the beginning of the ISR if we
|
||||
* have been context switched between the beginning of this invocation
|
||||
* of _ISR_Handler and this point. Thus the CWP and WIM should
|
||||
* not be changed back to their values at ISR entry time. Any
|
||||
* changes to the PSR must preserve the CWP.
|
||||
*/
|
||||
|
||||
simple_return:
|
||||
ld [%fp + ISF_Y_OFFSET], %l5 ! restore y
|
||||
wr %l5, 0, %y
|
||||
|
||||
ldd [%fp + ISF_PSR_OFFSET], %l0 ! restore psr, PC
|
||||
ld [%fp + ISF_NPC_OFFSET], %l2 ! restore nPC
|
||||
rd %psr, %l3
|
||||
and %l3, SPARC_PSR_CWP_MASK, %l3 ! want "current" CWP
|
||||
andn %l0, SPARC_PSR_CWP_MASK, %l0 ! want rest from task
|
||||
or %l3, %l0, %l0 ! install it later...
|
||||
andn %l0, SPARC_PSR_ET_MASK, %l0
|
||||
|
||||
/*
|
||||
* Restore tasks global and out registers
|
||||
*/
|
||||
|
||||
mov %fp, %g1
|
||||
|
||||
! g1 is restored later
|
||||
ldd [%fp + ISF_G2_OFFSET], %g2 ! restore g2, g3
|
||||
ldd [%fp + ISF_G4_OFFSET], %g4 ! restore g4, g5
|
||||
ldd [%fp + ISF_G6_OFFSET], %g6 ! restore g6, g7
|
||||
|
||||
ldd [%fp + ISF_I0_OFFSET], %i0 ! restore i0, i1
|
||||
ldd [%fp + ISF_I2_OFFSET], %i2 ! restore i2, i3
|
||||
ldd [%fp + ISF_I4_OFFSET], %i4 ! restore i4, i5
|
||||
ldd [%fp + ISF_I6_FP_OFFSET], %i6 ! restore i6/fp, i7
|
||||
|
||||
/*
|
||||
* Registers:
|
||||
*
|
||||
* ALL global registers EXCEPT G1 and the input registers have
|
||||
* already been restored and thuse off limits.
|
||||
*
|
||||
* The following is the contents of the local registers:
|
||||
*
|
||||
* l0 = original psr
|
||||
* l1 = return address (i.e. PC)
|
||||
* l2 = nPC
|
||||
* l3 = CWP
|
||||
*/
|
||||
|
||||
/*
|
||||
* if (CWP + 1) is an invalid window then we need to reload it.
|
||||
*
|
||||
* WARNING: Traps should now be disabled
|
||||
*/
|
||||
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
rd %wim, %l4
|
||||
add %l0, 1, %l6 ! l6 = cwp + 1
|
||||
and %l6, SPARC_PSR_CWP_MASK, %l6 ! do the modulo on it
|
||||
srl %l4, %l6, %l5 ! l5 = win >> cwp + 1 ; shift count
|
||||
! and CWP are conveniently LS 5 bits
|
||||
cmp %l5, 1 ! Is tasks window invalid?
|
||||
bne good_task_window
|
||||
|
||||
/*
|
||||
* The following code is the same as a 1 position left rotate of WIM.
|
||||
*/
|
||||
|
||||
sll %l4, 1, %l5 ! l5 = WIM << 1
|
||||
srl %l4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
|
||||
! l4 = WIM >> (Number Windows - 1)
|
||||
or %l4, %l5, %l4 ! l4 = (WIM << 1) |
|
||||
! (WIM >> (Number Windows - 1))
|
||||
|
||||
/*
|
||||
* Now restore the window just as if we underflowed to it.
|
||||
*/
|
||||
|
||||
wr %l4, 0, %wim ! WIM = new WIM
|
||||
restore ! now into the tasks window
|
||||
|
||||
ldd [%g1 + CPU_STACK_FRAME_L0_OFFSET], %l0
|
||||
ldd [%g1 + CPU_STACK_FRAME_L2_OFFSET], %l2
|
||||
ldd [%g1 + CPU_STACK_FRAME_L4_OFFSET], %l4
|
||||
ldd [%g1 + CPU_STACK_FRAME_L6_OFFSET], %l6
|
||||
ldd [%g1 + CPU_STACK_FRAME_I0_OFFSET], %i0
|
||||
ldd [%g1 + CPU_STACK_FRAME_I2_OFFSET], %i2
|
||||
ldd [%g1 + CPU_STACK_FRAME_I4_OFFSET], %i4
|
||||
ldd [%g1 + CPU_STACK_FRAME_I6_FP_OFFSET], %i6
|
||||
! reload of sp clobbers ISF
|
||||
save ! Back to ISR dispatch window
|
||||
|
||||
good_task_window:
|
||||
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
! and restore condition codes.
|
||||
ld [%g1 + ISF_G1_OFFSET], %g1 ! restore g1
|
||||
jmp %l1 ! transfer control and
|
||||
rett %l2 ! go back to tasks window
|
||||
|
||||
/* end of file */
|
||||
|
||||
503
c/src/exec/score/cpu/sparc/erc32.h
Normal file
503
c/src/exec/score/cpu/sparc/erc32.h
Normal file
@@ -0,0 +1,503 @@
|
||||
/* erc32.h
|
||||
*
|
||||
* This include file contains information pertaining to the ERC32.
|
||||
* The ERC32 is a custom SPARC V7 implementation based on the Cypress
|
||||
* 601/602 chipset. This CPU has a number of on-board peripherals and
|
||||
* was developed by the European Space Agency to target space applications.
|
||||
*
|
||||
* NOTE: Other than where absolutely required, this version currently
|
||||
* supports only the peripherals and bits used by the basic board
|
||||
* support package. This includes at least significant pieces of
|
||||
* the following items:
|
||||
*
|
||||
* + UART Channels A and B
|
||||
* + General Purpose Timer
|
||||
* + Real Time Clock
|
||||
* + Watchdog Timer (so it can be disabled)
|
||||
* + Control Register (so powerdown mode can be enabled)
|
||||
* + Memory Control Register
|
||||
* + Interrupt Control
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_ERC32_h
|
||||
#define _INCLUDE_ERC32_h
|
||||
|
||||
#include <rtems/score/sparc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt Sources
|
||||
*
|
||||
* The interrupt source numbers directly map to the trap type and to
|
||||
* the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask,
|
||||
* and the Interrupt Pending Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_INTERRUPT_MASKED_ERRORS 1
|
||||
#define ERC32_INTERRUPT_EXTERNAL_1 2
|
||||
#define ERC32_INTERRUPT_EXTERNAL_2 3
|
||||
#define ERC32_INTERRUPT_UART_A_RX_TX 4
|
||||
#define ERC32_INTERRUPT_UART_B_RX_TX 5
|
||||
#define ERC32_INTERRUPT_CORRECTABLE_MEMORY_ERROR 6
|
||||
#define ERC32_INTERRUPT_UART_ERROR 7
|
||||
#define ERC32_INTERRUPT_DMA_ACCESS_ERROR 8
|
||||
#define ERC32_INTERRUPT_DMA_TIMEOUT 9
|
||||
#define ERC32_INTERRUPT_EXTERNAL_3 10
|
||||
#define ERC32_INTERRUPT_EXTERNAL_4 11
|
||||
#define ERC32_INTERRUPT_GENERAL_PURPOSE_TIMER 12
|
||||
#define ERC32_INTERRUPT_REAL_TIME_CLOCK 13
|
||||
#define ERC32_INTERRUPT_EXTERNAL_5 14
|
||||
#define ERC32_INTERRUPT_WATCHDOG_TIMEOUT 15
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* Trap Types for on-chip peripherals
|
||||
*
|
||||
* Source: Table 8 - Interrupt Trap Type and Default Priority Assignments
|
||||
*
|
||||
* NOTE: The priority level for each source corresponds to the least
|
||||
* significant nibble of the trap type.
|
||||
*/
|
||||
|
||||
#define ERC32_TRAP_TYPE( _source ) SPARC_ASYNCHRONOUS_TRAP((_source) + 0x10)
|
||||
|
||||
#define ERC32_TRAP_SOURCE( _trap ) ((_trap) - 0x10)
|
||||
|
||||
#define ERC32_Is_MEC_Trap( _trap ) \
|
||||
( (_trap) >= ERC32_TRAP_TYPE( ERC32_INTERRUPT_MASKED_ERRORS ) && \
|
||||
(_trap) <= ERC32_TRAP_TYPE( ERC32_INTERRUPT_WATCHDOG_TIMEOUT ) )
|
||||
|
||||
/*
|
||||
* Structure for ERC32 memory mapped registers.
|
||||
*
|
||||
* Source: Section 3.25.2 - Register Address Map
|
||||
*
|
||||
* NOTE: There is only one of these structures per CPU, its base address
|
||||
* is 0x01f80000, and the variable MEC is placed there by the
|
||||
* linkcmds file.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned32 Control; /* offset 0x00 */
|
||||
volatile unsigned32 Software_Reset; /* offset 0x04 */
|
||||
volatile unsigned32 Power_Down; /* offset 0x08 */
|
||||
volatile unsigned32 Unimplemented_0; /* offset 0x0c */
|
||||
volatile unsigned32 Memory_Configuration; /* offset 0x10 */
|
||||
volatile unsigned32 IO_Configuration; /* offset 0x14 */
|
||||
volatile unsigned32 Wait_State_Configuration; /* offset 0x18 */
|
||||
volatile unsigned32 Unimplemented_1; /* offset 0x1c */
|
||||
volatile unsigned32 Memory_Access_0; /* offset 0x20 */
|
||||
volatile unsigned32 Memory_Access_1; /* offset 0x24 */
|
||||
volatile unsigned32 Unimplemented_2[ 7 ]; /* offset 0x28 */
|
||||
volatile unsigned32 Interrupt_Shape; /* offset 0x44 */
|
||||
volatile unsigned32 Interrupt_Pending; /* offset 0x48 */
|
||||
volatile unsigned32 Interrupt_Mask; /* offset 0x4c */
|
||||
volatile unsigned32 Interrupt_Clear; /* offset 0x50 */
|
||||
volatile unsigned32 Interrupt_Force; /* offset 0x54 */
|
||||
volatile unsigned32 Unimplemented_3[ 2 ]; /* offset 0x58 */
|
||||
/* offset 0x60 */
|
||||
volatile unsigned32 Watchdog_Program_and_Timeout_Acknowledge;
|
||||
volatile unsigned32 Watchdog_Trap_Door_Set; /* offset 0x64 */
|
||||
volatile unsigned32 Unimplemented_4[ 6 ]; /* offset 0x68 */
|
||||
volatile unsigned32 Real_Time_Clock_Counter; /* offset 0x80 */
|
||||
volatile unsigned32 Real_Time_Clock_Scalar; /* offset 0x84 */
|
||||
volatile unsigned32 General_Purpose_Timer_Counter; /* offset 0x88 */
|
||||
volatile unsigned32 General_Purpose_Timer_Scalar; /* offset 0x8c */
|
||||
volatile unsigned32 Unimplemented_5[ 2 ]; /* offset 0x90 */
|
||||
volatile unsigned32 Timer_Control; /* offset 0x98 */
|
||||
volatile unsigned32 Unimplemented_6; /* offset 0x9c */
|
||||
volatile unsigned32 System_Fault_Status; /* offset 0xa0 */
|
||||
volatile unsigned32 First_Failing_Address; /* offset 0xa4 */
|
||||
volatile unsigned32 First_Failing_Data; /* offset 0xa8 */
|
||||
volatile unsigned32 First_Failing_Syndrome_and_Check_Bits;/* offset 0xac */
|
||||
volatile unsigned32 Error_and_Reset_Status; /* offset 0xb0 */
|
||||
volatile unsigned32 Error_Mask; /* offset 0xb4 */
|
||||
volatile unsigned32 Unimplemented_7[ 2 ]; /* offset 0xb8 */
|
||||
volatile unsigned32 Debug_Control; /* offset 0xc0 */
|
||||
volatile unsigned32 Breakpoint; /* offset 0xc4 */
|
||||
volatile unsigned32 Watchpoint; /* offset 0xc8 */
|
||||
volatile unsigned32 Unimplemented_8; /* offset 0xcc */
|
||||
volatile unsigned32 Test_Control; /* offset 0xd0 */
|
||||
volatile unsigned32 Test_Data; /* offset 0xd4 */
|
||||
volatile unsigned32 Unimplemented_9[ 2 ]; /* offset 0xd8 */
|
||||
volatile unsigned32 UART_Channel_A; /* offset 0xe0 */
|
||||
volatile unsigned32 UART_Channel_B; /* offset 0xe4 */
|
||||
volatile unsigned32 UART_Status; /* offset 0xe8 */
|
||||
} ERC32_Register_Map;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following constants are intended to be used ONLY in assembly
|
||||
* language files.
|
||||
*
|
||||
* NOTE: The intended style of usage is to load the address of MEC
|
||||
* into a register and then use these as displacements from
|
||||
* that register.
|
||||
*/
|
||||
|
||||
#ifdef ASM
|
||||
|
||||
#define ERC32_MEC_CONTROL_OFFSET 0x00
|
||||
#define ERC32_MEC_SOFTWARE_RESET_OFFSET 0x04
|
||||
#define ERC32_MEC_POWER_DOWN_OFFSET 0x08
|
||||
#define ERC32_MEC_UNIMPLEMENTED_0_OFFSET 0x0C
|
||||
#define ERC32_MEC_MEMORY_CONFIGURATION_OFFSET 0x10
|
||||
#define ERC32_MEC_IO_CONFIGURATION_OFFSET 0x14
|
||||
#define ERC32_MEC_WAIT_STATE_CONFIGURATION_OFFSET 0x18
|
||||
#define ERC32_MEC_UNIMPLEMENTED_1_OFFSET 0x1C
|
||||
#define ERC32_MEC_MEMORY_ACCESS_0_OFFSET 0x20
|
||||
#define ERC32_MEC_MEMORY_ACCESS_1_OFFSET 0x24
|
||||
#define ERC32_MEC_UNIMPLEMENTED_2_OFFSET 0x28
|
||||
#define ERC32_MEC_INTERRUPT_SHAPE_OFFSET 0x44
|
||||
#define ERC32_MEC_INTERRUPT_PENDING_OFFSET 0x48
|
||||
#define ERC32_MEC_INTERRUPT_MASK_OFFSET 0x4C
|
||||
#define ERC32_MEC_INTERRUPT_CLEAR_OFFSET 0x50
|
||||
#define ERC32_MEC_INTERRUPT_FORCE_OFFSET 0x54
|
||||
#define ERC32_MEC_UNIMPLEMENTED_3_OFFSET 0x58
|
||||
#define ERC32_MEC_WATCHDOG_PROGRAM_AND_TIMEOUT_ACKNOWLEDGE_OFFSET 0x60
|
||||
#define ERC32_MEC_WATCHDOG_TRAP_DOOR_SET_OFFSET 0x64
|
||||
#define ERC32_MEC_UNIMPLEMENTED_4_OFFSET 0x6C
|
||||
#define ERC32_MEC_REAL_TIME_CLOCK_COUNTER_OFFSET 0x80
|
||||
#define ERC32_MEC_REAL_TIME_CLOCK_SCALAR_OFFSET 0x84
|
||||
#define ERC32_MEC_GENERAL_PURPOSE_TIMER_COUNTER_OFFSET 0x88
|
||||
#define ERC32_MEC_GENERAL_PURPOSE_TIMER_SCALAR_OFFSET 0x8C
|
||||
#define ERC32_MEC_UNIMPLEMENTED_5_OFFSET 0x90
|
||||
#define ERC32_MEC_TIMER_CONTROL_OFFSET 0x98
|
||||
#define ERC32_MEC_UNIMPLEMENTED_6_OFFSET 0x9C
|
||||
#define ERC32_MEC_SYSTEM_FAULT_STATUS_OFFSET 0xA0
|
||||
#define ERC32_MEC_FIRST_FAILING_ADDRESS_OFFSET 0xA4
|
||||
#define ERC32_MEC_FIRST_FAILING_DATA_OFFSET 0xA8
|
||||
#define ERC32_MEC_FIRST_FAILING_SYNDROME_AND_CHECK_BITS_OFFSET 0xAC
|
||||
#define ERC32_MEC_ERROR_AND_RESET_STATUS_OFFSET 0xB0
|
||||
#define ERC32_MEC_ERROR_MASK_OFFSET 0xB4
|
||||
#define ERC32_MEC_UNIMPLEMENTED_7_OFFSET 0xB8
|
||||
#define ERC32_MEC_DEBUG_CONTROL_OFFSET 0xC0
|
||||
#define ERC32_MEC_BREAKPOINT_OFFSET 0xC4
|
||||
#define ERC32_MEC_WATCHPOINT_OFFSET 0xC8
|
||||
#define ERC32_MEC_UNIMPLEMENTED_8_OFFSET 0xCC
|
||||
#define ERC32_MEC_TEST_CONTROL_OFFSET 0xD0
|
||||
#define ERC32_MEC_TEST_DATA_OFFSET 0xD4
|
||||
#define ERC32_MEC_UNIMPLEMENTED_9_OFFSET 0xD8
|
||||
#define ERC32_MEC_UART_CHANNEL_A_OFFSET 0xE0
|
||||
#define ERC32_MEC_UART_CHANNEL_B_OFFSET 0xE4
|
||||
#define ERC32_MEC_UART_STATUS_OFFSET 0xE8
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Configuration Register.
|
||||
*/
|
||||
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_MASK 0x00000001
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_ALLOWED 0x00000001
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_MASK 0x00000002
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_ALLOWED 0x00000002
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_MASK 0x00000004
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_ENABLED 0x00000004
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_MASK 0x00000008
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_ENABLED 0x00000008
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_DISABLED 0x00000000
|
||||
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Memory Configuration Register.
|
||||
*/
|
||||
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_MASK 0x00001C00
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_256K ( 0 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_512K ( 1 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_1MB ( 2 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_2MB ( 3 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_4MB ( 4 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_8MB ( 5 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_16MB ( 6 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_32MB ( 7 << 10 )
|
||||
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_MASK 0x001C0000
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_4K ( 0 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_8K ( 1 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_16K ( 2 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_32K ( 3 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_64K ( 4 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_128K ( 5 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_256K ( 6 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_512K ( 7 << 18 )
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Timer Control Register.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_TIMER_CONTROL_GCR 0x00000001 /* 1 = reload at 0 */
|
||||
/* 0 = stop at 0 */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GCL 0x00000002 /* 1 = load and start */
|
||||
/* 0 = no function */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GSE 0x00000004 /* 1 = enable counting */
|
||||
/* 0 = hold scalar and counter */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GSL 0x00000008 /* 1 = load scalar and start */
|
||||
/* 0 = no function */
|
||||
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCCR 0x00000100 /* 1 = reload at 0 */
|
||||
/* 0 = stop at 0 */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCCL 0x00000200 /* 1 = load and start */
|
||||
/* 0 = no function */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCSE 0x00000400 /* 1 = enable counting */
|
||||
/* 0 = hold scalar and counter */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCSL 0x00000800 /* 1 = load scalar and start */
|
||||
/* 0 = no function */
|
||||
|
||||
/*
|
||||
* The following defines the bits in the UART Control Registers.
|
||||
*
|
||||
* NOTE: Same bits in UART channels A and B.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_UART_CONTROL_RTD 0x000000FF /* RX/TX data */
|
||||
#define ERC32_MEC_UART_CONTROL_DR 0x00000100 /* RX Data Ready */
|
||||
#define ERC32_MEC_UART_CONTROL_TSE 0x00000200 /* TX Send Empty */
|
||||
/* (i.e. no data to send) */
|
||||
#define ERC32_MEC_UART_CONTROL_THE 0x00000400 /* TX Hold Empty */
|
||||
/* (i.e. ready to load) */
|
||||
|
||||
/*
|
||||
* The following defines the bits in the MEC UART Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DR 0x00000001 /* Data Ready */
|
||||
#define ERC32_MEC_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
|
||||
#define ERC32_MEC_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
|
||||
#define ERC32_MEC_UART_STATUS_FE 0x00000010 /* RX Framing Error */
|
||||
#define ERC32_MEC_UART_STATUS_PE 0x00000020 /* RX Parity Error */
|
||||
#define ERC32_MEC_UART_STATUS_OE 0x00000040 /* RX Overrun Error */
|
||||
#define ERC32_MEC_UART_STATUS_CU 0x00000080 /* Clear Errors */
|
||||
#define ERC32_MEC_UART_STATUS_TXE 0x00000006 /* TX Empty */
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DRA (ERC32_MEC_UART_STATUS_DR << 0)
|
||||
#define ERC32_MEC_UART_STATUS_TSEA (ERC32_MEC_UART_STATUS_TSE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_THEA (ERC32_MEC_UART_STATUS_THE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_FEA (ERC32_MEC_UART_STATUS_FE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_PEA (ERC32_MEC_UART_STATUS_PE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_OEA (ERC32_MEC_UART_STATUS_OE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_CUA (ERC32_MEC_UART_STATUS_CU << 0)
|
||||
#define ERC32_MEC_UART_STATUS_TXEA (ERC32_MEC_UART_STATUS_TXE << 0)
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DRB (ERC32_MEC_UART_STATUS_DR << 16)
|
||||
#define ERC32_MEC_UART_STATUS_TSEB (ERC32_MEC_UART_STATUS_TSE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_THEB (ERC32_MEC_UART_STATUS_THE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_FEB (ERC32_MEC_UART_STATUS_FE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_PEB (ERC32_MEC_UART_STATUS_PE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_OEB (ERC32_MEC_UART_STATUS_OE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_CUB (ERC32_MEC_UART_STATUS_CU << 16)
|
||||
#define ERC32_MEC_UART_STATUS_TXEB (ERC32_MEC_UART_STATUS_TXE << 16)
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* This is used to manipulate the on-chip registers.
|
||||
*
|
||||
* The following symbol must be defined in the linkcmds file and point
|
||||
* to the correct location.
|
||||
*/
|
||||
|
||||
extern ERC32_Register_Map ERC32_MEC;
|
||||
|
||||
/*
|
||||
* Macros to manipulate the Interrupt Clear, Interrupt Force, Interrupt Mask,
|
||||
* and the Interrupt Pending Registers.
|
||||
*
|
||||
* NOTE: For operations which are not atomic, this code disables interrupts
|
||||
* to guarantee there are no intervening accesses to the same register.
|
||||
* The operations which read the register, modify the value and then
|
||||
* store the result back are vulnerable.
|
||||
*/
|
||||
|
||||
#define ERC32_Clear_interrupt( _source ) \
|
||||
do { \
|
||||
ERC32_MEC.Interrupt_Clear = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Force_interrupt( _source ) \
|
||||
do { \
|
||||
ERC32_MEC.Interrupt_Force = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Is_interrupt_pending( _source ) \
|
||||
(ERC32_MEC.Interrupt_Pending & (1 << (_source)))
|
||||
|
||||
#define ERC32_Is_interrupt_masked( _source ) \
|
||||
(ERC32_MEC.Interrupt_Masked & (1 << (_source)))
|
||||
|
||||
#define ERC32_Mask_interrupt( _source ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask |= (1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Unmask_interrupt( _source ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask &= ~(1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Disable_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _mask = 1 << (_source); \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
(_previous) = ERC32_MEC.Interrupt_Mask; \
|
||||
ERC32_MEC.Interrupt_Mask = _previous | _mask; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
(_previous) &= ~_mask; \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Restore_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _mask = 1 << (_source); \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask = \
|
||||
(ERC32_MEC.Interrupt_Mask & ~_mask) | (_previous); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The following macros attempt to hide the fact that the General Purpose
|
||||
* Timer and Real Time Clock Timer share the Timer Control Register. Because
|
||||
* the Timer Control Register is write only, we must mirror it in software
|
||||
* and insure that writes to one timer do not alter the current settings
|
||||
* and status of the other timer.
|
||||
*
|
||||
* This code promotes the view that the two timers are completely independent.
|
||||
* By exclusively using the routines below to access the Timer Control
|
||||
* Register, the application can view the system as having a General Purpose
|
||||
* Timer Control Register and a Real Time Clock Timer Control Register
|
||||
* rather than the single shared value.
|
||||
*
|
||||
* Each logical timer control register is organized as follows:
|
||||
*
|
||||
* D0 - Counter Reload
|
||||
* 1 = reload counter at zero and restart
|
||||
* 0 = stop counter at zero
|
||||
*
|
||||
* D1 - Counter Load
|
||||
* 1 = load counter with preset value and restart
|
||||
* 0 = no function
|
||||
*
|
||||
* D2 - Enable
|
||||
* 1 = enable counting
|
||||
* 0 = hold scaler and counter
|
||||
*
|
||||
* D2 - Scaler Load
|
||||
* 1 = load scalar with preset value and restart
|
||||
* 0 = no function
|
||||
*
|
||||
* To insure the management of the mirror is atomic, we disable interrupts
|
||||
* around updates.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO 0x00000001
|
||||
#define ERC32_MEC_TIMER_COUNTER_STOP_AT_ZERO 0x00000000
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER 0x00000002
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING 0x00000004
|
||||
#define ERC32_MEC_TIMER_COUNTER_DISABLE_COUNTING 0x00000000
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_LOAD_SCALER 0x00000008
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_RELOAD_MASK 0x00000001
|
||||
#define ERC32_MEC_TIMER_COUNTER_ENABLE_MASK 0x00000004
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_DEFINED_MASK 0x0000000F
|
||||
#define ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000005
|
||||
|
||||
extern unsigned32 _ERC32_MEC_Timer_Control_Mirror;
|
||||
|
||||
/*
|
||||
* This macros manipulate the General Purpose Timer portion of the
|
||||
* Timer Control register and promote the view that there are actually
|
||||
* two independent Timer Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_Set_General_Purpose_Timer_Control( _value ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _control; \
|
||||
unsigned32 __value; \
|
||||
\
|
||||
__value = ((_value) & 0x0f); \
|
||||
sparc_disable_interrupts( _level ); \
|
||||
_control = _ERC32_MEC_Timer_Control_Mirror; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK << 8; \
|
||||
_ERC32_MEC_Timer_Control_Mirror = _control | _value; \
|
||||
_control &= (ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK << 8); \
|
||||
_control |= __value; \
|
||||
/* printf( "GPT 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
|
||||
ERC32_MEC.Timer_Control = _control; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define ERC32_MEC_Get_General_Purpose_Timer_Control( _value ) \
|
||||
do { \
|
||||
(_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* This macros manipulate the Real Timer Clock Timer portion of the
|
||||
* Timer Control register and promote the view that there are actually
|
||||
* two independent Timer Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_Set_Real_Time_Clock_Timer_Control( _value ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _control; \
|
||||
unsigned32 __value; \
|
||||
\
|
||||
__value = ((_value) & 0x0f) << 8; \
|
||||
sparc_disable_interrupts( _level ); \
|
||||
_control = _ERC32_MEC_Timer_Control_Mirror; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK; \
|
||||
_ERC32_MEC_Timer_Control_Mirror = _control | _value; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK; \
|
||||
_control |= __value; \
|
||||
/* printf( "RTC 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
|
||||
ERC32_MEC.Timer_Control = _control; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define ERC32_MEC_Get_Real_Time_Clock_Timer_Control( _value ) \
|
||||
do { \
|
||||
(_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_INCLUDE_ERC32_h */
|
||||
/* end of include file */
|
||||
|
||||
@@ -22,12 +22,22 @@
|
||||
* is used to look up the directive.
|
||||
*
|
||||
* void RTEMS()
|
||||
* {
|
||||
* }
|
||||
*/
|
||||
|
||||
.align 4
|
||||
PUBLIC(RTEMS)
|
||||
SYM(RTEMS):
|
||||
ret
|
||||
/*
|
||||
* g2 was chosen because gcc uses it as a scratch register in
|
||||
* similar code scenarios and the other locals, ins, and outs
|
||||
* are off limits to this routine unless it does a "save" and
|
||||
* copies its in registers to the outs which only works up until
|
||||
* 6 parameters. Best to take the simple approach in this case.
|
||||
*/
|
||||
sethi SYM(_Entry_points), %g2
|
||||
or %g2, %lo(SYM(_Entry_points)), %g2
|
||||
sll %g1, 2, %g1
|
||||
add %g1, %g2, %g2
|
||||
jmp %g2
|
||||
nop
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* sparc.h
|
||||
*
|
||||
* This include file contains information pertaining to the Motorola
|
||||
* SPARC processor family.
|
||||
* This include file contains information pertaining to the SPARC
|
||||
* processor family.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
@@ -37,8 +37,7 @@ extern "C" {
|
||||
|
||||
/*
|
||||
* This file contains the information required to build
|
||||
* RTEMS for a particular member of the "sparc"
|
||||
* family when executing in protected mode. It does
|
||||
* RTEMS for a particular member of the "sparc" family. It does
|
||||
* this by setting variables to indicate which implementation
|
||||
* dependent features are present in a particular member
|
||||
* of the family.
|
||||
@@ -51,7 +50,15 @@ extern "C" {
|
||||
*
|
||||
* + SPARC_HAS_BITSCAN
|
||||
* 0 - does not have scan instructions
|
||||
* 1 - has scan instruction (no support implemented)
|
||||
* 1 - has scan instruction (not currently implemented)
|
||||
*
|
||||
* + SPARC_NUMBER_OF_REGISTER_WINDOWS
|
||||
* 8 is the most common number supported by SPARC implementations.
|
||||
* SPARC_PSR_CWP_MASK is derived from this value.
|
||||
*
|
||||
* + SPARC_HAS_LOW_POWER_MODE
|
||||
* 0 - does not have low power mode support (or not supported)
|
||||
* 1 - has low power mode and thus a CPU model dependent idle task.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -60,6 +67,8 @@ extern "C" {
|
||||
#define CPU_MODEL_NAME "erc32"
|
||||
#define SPARC_HAS_FPU 1
|
||||
#define SPARC_HAS_BITSCAN 0
|
||||
#define SPARC_NUMBER_OF_REGISTER_WINDOWS 8
|
||||
#define SPARC_HAS_LOW_POWER_MODE 1
|
||||
|
||||
#else
|
||||
|
||||
@@ -73,6 +82,49 @@ extern "C" {
|
||||
|
||||
#define CPU_NAME "SPARC"
|
||||
|
||||
/*
|
||||
* Miscellaneous constants
|
||||
*/
|
||||
|
||||
/*
|
||||
* PSR masks and starting bit positions
|
||||
*
|
||||
* NOTE: Reserved bits are ignored.
|
||||
*/
|
||||
|
||||
#if (SPARC_NUMBER_OF_REGISTER_WINDOWS == 8)
|
||||
#define SPARC_PSR_CWP_MASK 0x07 /* bits 0 - 4 */
|
||||
#elif (SPARC_NUMBER_OF_REGISTER_WINDOWS == 16)
|
||||
#define SPARC_PSR_CWP_MASK 0x0F /* bits 0 - 4 */
|
||||
#elif (SPARC_NUMBER_OF_REGISTER_WINDOWS == 32)
|
||||
#define SPARC_PSR_CWP_MASK 0x1F /* bits 0 - 4 */
|
||||
#else
|
||||
#error "Unsupported number of register windows for this cpu"
|
||||
#endif
|
||||
|
||||
#define SPARC_PSR_ET_MASK 0x00000020 /* bit 5 */
|
||||
#define SPARC_PSR_PS_MASK 0x00000040 /* bit 6 */
|
||||
#define SPARC_PSR_S_MASK 0x00000080 /* bit 7 */
|
||||
#define SPARC_PSR_PIL_MASK 0x00000F00 /* bits 8 - 11 */
|
||||
#define SPARC_PSR_EF_MASK 0x00001000 /* bit 12 */
|
||||
#define SPARC_PSR_EC_MASK 0x00002000 /* bit 13 */
|
||||
#define SPARC_PSR_ICC_MASK 0x00F00000 /* bits 20 - 23 */
|
||||
#define SPARC_PSR_VER_MASK 0x0F000000 /* bits 24 - 27 */
|
||||
#define SPARC_PSR_IMPL_MASK 0xF0000000 /* bits 28 - 31 */
|
||||
|
||||
#define SPARC_PSR_CWP_BIT_POSITION 0 /* bits 0 - 4 */
|
||||
#define SPARC_PSR_ET_BIT_POSITION 5 /* bit 5 */
|
||||
#define SPARC_PSR_PS_BIT_POSITION 6 /* bit 6 */
|
||||
#define SPARC_PSR_S_BIT_POSITION 7 /* bit 7 */
|
||||
#define SPARC_PSR_PIL_BIT_POSITION 8 /* bits 8 - 11 */
|
||||
#define SPARC_PSR_EF_BIT_POSITION 12 /* bit 12 */
|
||||
#define SPARC_PSR_EC_BIT_POSITION 13 /* bit 13 */
|
||||
#define SPARC_PSR_ICC_BIT_POSITION 20 /* bits 20 - 23 */
|
||||
#define SPARC_PSR_VER_BIT_POSITION 24 /* bits 24 - 27 */
|
||||
#define SPARC_PSR_IMPL_BIT_POSITION 28 /* bits 28 - 31 */
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* Standard nop
|
||||
*/
|
||||
@@ -83,7 +135,7 @@ extern "C" {
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* Some macros to aid in accessing special registers.
|
||||
* Get and set the PSR
|
||||
*/
|
||||
|
||||
#define sparc_get_psr( _psr ) \
|
||||
@@ -94,19 +146,31 @@ extern "C" {
|
||||
|
||||
#define sparc_set_psr( _psr ) \
|
||||
do { \
|
||||
asm volatile ( "wr %%g0,%0,%%psr " : "=r" ((_psr)) : "0" ((_psr)) ); \
|
||||
nop(); nop(); nop(); \
|
||||
asm volatile ( "mov %0, %%psr " : "=r" ((_psr)) : "0" ((_psr)) ); \
|
||||
nop(); \
|
||||
nop(); \
|
||||
nop(); \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* Get and set the TBR
|
||||
*/
|
||||
|
||||
#define sparc_get_tbr( _tbr ) \
|
||||
do { \
|
||||
(_tbr) = 0; /* to avoid unitialized warnings */ \
|
||||
asm volatile( "rd %%tbr, %0" : "=r" (_tbr) : "0" (_tbr) ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define sparc_set_tbr( _tbr ) \
|
||||
do { \
|
||||
asm volatile( "wr %0, 0, %%tbr" : "=r" (_tbr) : "0" (_tbr) ); \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* Get and set the WIM
|
||||
*/
|
||||
|
||||
#define sparc_get_wim( _wim ) \
|
||||
do { \
|
||||
asm volatile( "rd %%wim, %0" : "=r" (_wim) : "0" (_wim) ); \
|
||||
@@ -114,6 +178,24 @@ extern "C" {
|
||||
|
||||
#define sparc_set_wim( _wim ) \
|
||||
do { \
|
||||
asm volatile( "wr %0, %%wim" : "=r" (_wim) : "0" (_wim) ); \
|
||||
nop(); \
|
||||
nop(); \
|
||||
nop(); \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* Get and set the Y
|
||||
*/
|
||||
|
||||
#define sparc_get_y( _y ) \
|
||||
do { \
|
||||
asm volatile( "rd %%y, %0" : "=r" (_y) : "0" (_y) ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define sparc_set_y( _y ) \
|
||||
do { \
|
||||
asm volatile( "wr %0, %%y" : "=r" (_y) : "0" (_y) ); \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
@@ -121,42 +203,41 @@ extern "C" {
|
||||
*
|
||||
*/
|
||||
|
||||
#define SPARC_PIL_MASK 0x00000F00
|
||||
|
||||
#define sparc_disable_interrupts( _level ) \
|
||||
do { register unsigned int _mask = SPARC_PIL_MASK; \
|
||||
(_level) = 0; \
|
||||
do { \
|
||||
register unsigned int _newlevel; \
|
||||
\
|
||||
asm volatile ( "rd %%psr,%0 ; \
|
||||
wr %0,%1,%%psr " \
|
||||
: "=r" ((_level)), "=r" (_mask) \
|
||||
: "0" ((_level)), "1" (_mask) \
|
||||
); \
|
||||
nop(); nop(); nop(); \
|
||||
sparc_get_psr( _level ); \
|
||||
(_newlevel) = (_level) | SPARC_PSR_PIL_MASK; \
|
||||
sparc_set_psr( _newlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define sparc_enable_interrupts( _level ) \
|
||||
do { unsigned int _tmp; \
|
||||
do { \
|
||||
unsigned int _tmp; \
|
||||
\
|
||||
sparc_get_psr( _tmp ); \
|
||||
_tmp &= ~SPARC_PIL_MASK; \
|
||||
_tmp |= (_level) & SPARC_PIL_MASK; \
|
||||
_tmp &= ~SPARC_PSR_PIL_MASK; \
|
||||
_tmp |= (_level) & SPARC_PSR_PIL_MASK; \
|
||||
sparc_set_psr( _tmp ); \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#define sparc_flash_interrupts( _level ) \
|
||||
do { \
|
||||
register unsigned32 _ignored = 0; \
|
||||
\
|
||||
sparc_enable_interrupts( (_level) ); \
|
||||
sparc_disable_interrupts( _ignored ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define sparc_set_interrupt_level( _new_level ) \
|
||||
do { register unsigned32 _new_psr_level = 0; \
|
||||
do { \
|
||||
register unsigned32 _new_psr_level = 0; \
|
||||
\
|
||||
sparc_get_psr( _new_psr_level ); \
|
||||
_new_psr_level &= ~SPARC_PIL_MASK; \
|
||||
_new_psr_level |= (((_new_level) << 8) & SPARC_PIL_MASK); \
|
||||
_new_psr_level &= ~SPARC_PSR_PIL_MASK; \
|
||||
_new_psr_level |= \
|
||||
(((_new_level) << SPARC_PSR_PIL_BIT_POSITION) & SPARC_PSR_PIL_MASK); \
|
||||
sparc_set_psr( _new_psr_level ); \
|
||||
} while ( 0 )
|
||||
|
||||
@@ -165,9 +246,12 @@ extern "C" {
|
||||
register unsigned32 _psr_level = 0; \
|
||||
\
|
||||
sparc_get_psr( _psr_level ); \
|
||||
(_level) = (_psr_level & SPARC_PIL_MASK) >> 8; \
|
||||
(_level) = \
|
||||
(_psr_level & SPARC_PSR_PIL_MASK) >> SPARC_PSR_PIL_BIT_POSITION; \
|
||||
} while ( 0 )
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* sparctypes.h
|
||||
*
|
||||
* This include file contains type definitions pertaining to the Intel
|
||||
* This include file contains type definitions pertaining to the
|
||||
* SPARC processor family.
|
||||
*
|
||||
* $Id$
|
||||
|
||||
@@ -341,17 +341,10 @@ void _CPU_Install_interrupt_stack( void )
|
||||
*
|
||||
* _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.
|
||||
* Stop until we get a signal which is the logically the same thing
|
||||
* entering low-power or sleep mode on a real processor and waiting for
|
||||
* an interrupt. This significantly reduces the consumption of host
|
||||
* CPU cycles which is again similar to low power mode.
|
||||
*/
|
||||
|
||||
void _CPU_Internal_threads_Idle_thread_body( void )
|
||||
@@ -370,7 +363,8 @@ void _CPU_Context_Initialize(
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
void *_entry_point,
|
||||
boolean _is_fp
|
||||
)
|
||||
{
|
||||
void *source;
|
||||
@@ -697,49 +691,15 @@ void _CPU_Fatal_error(unsigned32 error)
|
||||
_exit(error);
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ffs
|
||||
*/
|
||||
|
||||
int _CPU_ffs(unsigned32 value)
|
||||
{
|
||||
int output;
|
||||
extern int ffs( int );
|
||||
|
||||
output = ffs(value);
|
||||
output = output - 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Special Purpose Routines to hide the use of UNIX system calls.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* XXX clock had this set of #define's */
|
||||
|
||||
/*
|
||||
* In order to get the types and prototypes used in this file under
|
||||
* Solaris 2.3, it is necessary to pull the following magic.
|
||||
*/
|
||||
|
||||
#if defined(solaris)
|
||||
#warning "Ignore the undefining __STDC__ warning"
|
||||
#undef __STDC__
|
||||
#define __STDC__ 0
|
||||
#undef _POSIX_C_SOURCE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int _CPU_Get_clock_vector( void )
|
||||
{
|
||||
return SIGALRM;
|
||||
}
|
||||
|
||||
|
||||
void _CPU_Start_clock(
|
||||
int microseconds
|
||||
)
|
||||
|
||||
@@ -550,6 +550,7 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
|
||||
*/
|
||||
|
||||
#define CPU_INTERRUPT_NUMBER_OF_VECTORS 64
|
||||
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1)
|
||||
|
||||
/*
|
||||
* Should be large enough to run all RTEMS tests. This insures
|
||||
@@ -721,7 +722,8 @@ extern void _CPU_Context_Initialize(
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
void *_entry_point,
|
||||
boolean _is_fp
|
||||
);
|
||||
|
||||
/* end of Context handler macros */
|
||||
@@ -757,11 +759,11 @@ extern void _CPU_Context_Initialize(
|
||||
*
|
||||
* RTEMS guarantees that (1) will never happen so it is not a concern.
|
||||
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
|
||||
* _CPU_Priority_Bits_index(). These three form a set of routines
|
||||
* _CPU_Priority_bits_index(). These three form a set of routines
|
||||
* which must logically operate together. Bits in the _value are
|
||||
* set and cleared based on masks built by _CPU_Priority_mask().
|
||||
* The basic major and minor values calculated by _Priority_Major()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
|
||||
* and _Priority_Minor() are "massaged" by _CPU_Priority_bits_index()
|
||||
* to properly range between the values returned by the "find first bit"
|
||||
* instruction. This makes it possible for _Priority_Get_highest() to
|
||||
* calculate the major and directly index into the minor table.
|
||||
@@ -796,30 +798,25 @@ extern void _CPU_Context_Initialize(
|
||||
* bit set
|
||||
*/
|
||||
|
||||
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||
_output = _CPU_ffs( _value )
|
||||
/*
|
||||
* The UNIX port uses the generic C algorithm for bitfield scan to avoid
|
||||
* dependencies on either a native bitscan instruction or an ffs() in the
|
||||
* C library.
|
||||
*/
|
||||
|
||||
#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
|
||||
#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
|
||||
|
||||
/* end of Bitfield handler macros */
|
||||
|
||||
/*
|
||||
* This routine builds the mask which corresponds to the bit fields
|
||||
* as searched by _CPU_Bitfield_Find_first_bit(). See the discussion
|
||||
* for that routine.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Mask( _bit_number ) \
|
||||
( 1 << (_bit_number) )
|
||||
/* Priority handler handler macros */
|
||||
|
||||
/*
|
||||
* This routine translates the bit numbers returned by
|
||||
* _CPU_Bitfield_Find_first_bit() into something suitable for use as
|
||||
* a major or minor component of a priority. See the discussion
|
||||
* for that routine.
|
||||
* The UNIX port uses the generic C algorithm for bitfield scan to avoid
|
||||
* dependencies on either a native bitscan instruction or an ffs() in the
|
||||
* C library.
|
||||
*/
|
||||
|
||||
#define _CPU_Priority_Bits_index( _priority ) \
|
||||
(_priority)
|
||||
|
||||
/* end of Priority handler macros */
|
||||
|
||||
/* functions */
|
||||
@@ -935,10 +932,6 @@ void _CPU_Fatal_error(
|
||||
unsigned32 _error
|
||||
);
|
||||
|
||||
int _CPU_ffs(
|
||||
unsigned32 _value
|
||||
);
|
||||
|
||||
/* The following routine swaps the endian format of an unsigned int.
|
||||
* It must be static because it is referenced indirectly.
|
||||
*
|
||||
|
||||
@@ -38,9 +38,58 @@ extern "C" {
|
||||
* significant impact on the performance of the executive as a whole.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_DATA == TRUE )
|
||||
|
||||
#ifndef INIT
|
||||
extern const unsigned char __log2table[256];
|
||||
#else
|
||||
const unsigned char __log2table[256] = {
|
||||
7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == FALSE )
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
_CPU_Bitfield_Find_first_bit( _value, _bit_number )
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* The following must be a macro because if a CPU specific version
|
||||
* is used it will most likely use inline assembly.
|
||||
*/
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
{ \
|
||||
register __value = (_value); \
|
||||
register const unsigned char *__p = __log2table; \
|
||||
\
|
||||
if ( __value < 0x100 ) \
|
||||
(_bit_number) = __p[ __value ] + 8; \
|
||||
else \
|
||||
(_bit_number) = __p[ __value >> 8 ]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,8 +47,9 @@ EXTERN boolean _Context_Switch_necessary;
|
||||
* thread's initial state.
|
||||
*/
|
||||
|
||||
#define _Context_Initialize( _the_context, _stack, _size, _isr, _entry ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry )
|
||||
#define \
|
||||
_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp )
|
||||
|
||||
/*
|
||||
* _Context_Switch
|
||||
|
||||
@@ -50,12 +50,19 @@ typedef ISR_Handler ( *ISR_Handler_entry )(
|
||||
ISR_Vector_number
|
||||
);
|
||||
/*
|
||||
* This constant promotes out the number of vectors supported by
|
||||
* the current CPU being used.
|
||||
* This constant promotes out the number of vectors truly supported by
|
||||
* the current CPU being used. This is usually the number of distinct vectors
|
||||
* the cpu can vector.
|
||||
*/
|
||||
|
||||
#define ISR_NUMBER_OF_VECTORS CPU_INTERRUPT_NUMBER_OF_VECTORS
|
||||
|
||||
/*
|
||||
* This constant promotes out the highest valid interrupt vector number.
|
||||
*/
|
||||
|
||||
#define ISR_INTERRUPT_MAXIMUM_VECTOR_NUMBER CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER
|
||||
|
||||
/*
|
||||
* The following is TRUE if signals have been sent to the currently
|
||||
* executing thread by an ISR handler.
|
||||
@@ -75,7 +82,7 @@ EXTERN unsigned32 _ISR_Nest_level;
|
||||
* interrupt service routines are vectored by the ISR Handler via this table.
|
||||
*/
|
||||
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[CPU_INTERRUPT_NUMBER_OF_VECTORS];
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _ISR_Handler_initialization
|
||||
|
||||
@@ -113,6 +113,51 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
Priority_Control the_priority
|
||||
);
|
||||
|
||||
/*
|
||||
* _Priority_Mask
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function returns the mask associated with the major or minor
|
||||
* number passed to it.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
_CPU_Priority_Mask( _bit_number )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function translates the bit numbers returned by the bit scan
|
||||
* of a priority bit field into something suitable for use as
|
||||
* a major or minor component of a priority.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Bits_index( _priority ) \
|
||||
_CPU_Priority_bits_index( _priority )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Add_to_bit_map
|
||||
*
|
||||
|
||||
@@ -38,9 +38,58 @@ extern "C" {
|
||||
* significant impact on the performance of the executive as a whole.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_DATA == TRUE )
|
||||
|
||||
#ifndef INIT
|
||||
extern const unsigned char __log2table[256];
|
||||
#else
|
||||
const unsigned char __log2table[256] = {
|
||||
7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == FALSE )
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
_CPU_Bitfield_Find_first_bit( _value, _bit_number )
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* The following must be a macro because if a CPU specific version
|
||||
* is used it will most likely use inline assembly.
|
||||
*/
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
{ \
|
||||
register __value = (_value); \
|
||||
register const unsigned char *__p = __log2table; \
|
||||
\
|
||||
if ( __value < 0x100 ) \
|
||||
(_bit_number) = __p[ __value ] + 8; \
|
||||
else \
|
||||
(_bit_number) = __p[ __value >> 8 ]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,8 +47,9 @@ EXTERN boolean _Context_Switch_necessary;
|
||||
* thread's initial state.
|
||||
*/
|
||||
|
||||
#define _Context_Initialize( _the_context, _stack, _size, _isr, _entry ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry )
|
||||
#define \
|
||||
_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp )
|
||||
|
||||
/*
|
||||
* _Context_Switch
|
||||
|
||||
@@ -50,12 +50,19 @@ typedef ISR_Handler ( *ISR_Handler_entry )(
|
||||
ISR_Vector_number
|
||||
);
|
||||
/*
|
||||
* This constant promotes out the number of vectors supported by
|
||||
* the current CPU being used.
|
||||
* This constant promotes out the number of vectors truly supported by
|
||||
* the current CPU being used. This is usually the number of distinct vectors
|
||||
* the cpu can vector.
|
||||
*/
|
||||
|
||||
#define ISR_NUMBER_OF_VECTORS CPU_INTERRUPT_NUMBER_OF_VECTORS
|
||||
|
||||
/*
|
||||
* This constant promotes out the highest valid interrupt vector number.
|
||||
*/
|
||||
|
||||
#define ISR_INTERRUPT_MAXIMUM_VECTOR_NUMBER CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER
|
||||
|
||||
/*
|
||||
* The following is TRUE if signals have been sent to the currently
|
||||
* executing thread by an ISR handler.
|
||||
@@ -75,7 +82,7 @@ EXTERN unsigned32 _ISR_Nest_level;
|
||||
* interrupt service routines are vectored by the ISR Handler via this table.
|
||||
*/
|
||||
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[CPU_INTERRUPT_NUMBER_OF_VECTORS];
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _ISR_Handler_initialization
|
||||
|
||||
@@ -113,6 +113,51 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
Priority_Control the_priority
|
||||
);
|
||||
|
||||
/*
|
||||
* _Priority_Mask
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function returns the mask associated with the major or minor
|
||||
* number passed to it.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
_CPU_Priority_Mask( _bit_number )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function translates the bit numbers returned by the bit scan
|
||||
* of a priority bit field into something suitable for use as
|
||||
* a major or minor component of a priority.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Bits_index( _priority ) \
|
||||
_CPU_Priority_bits_index( _priority )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Add_to_bit_map
|
||||
*
|
||||
|
||||
@@ -38,7 +38,7 @@ STATIC INLINE boolean _ISR_Is_vector_number_valid (
|
||||
unsigned32 vector
|
||||
)
|
||||
{
|
||||
return ( vector < CPU_INTERRUPT_NUMBER_OF_VECTORS );
|
||||
return ( vector <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
|
||||
@@ -78,6 +78,37 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
return ( the_priority % 16 );
|
||||
}
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return (0x8000 >> bit_number);
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return bit_number;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -121,8 +152,8 @@ STATIC INLINE Priority_Control _Priority_Get_highest( void )
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major );
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor );
|
||||
|
||||
return (_CPU_Priority_Bits_index( major ) << 4) +
|
||||
_CPU_Priority_Bits_index( minor );
|
||||
return (_Priority_Bits_index( major ) << 4) +
|
||||
_Priority_Bits_index( minor );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -144,13 +175,13 @@ STATIC INLINE void _Priority_Initialize_information(
|
||||
minor = _Priority_Minor( new_priority );
|
||||
|
||||
the_priority_map->minor =
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(major) ];
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(major) ];
|
||||
|
||||
mask = _CPU_Priority_Mask( major );
|
||||
mask = _Priority_Mask( major );
|
||||
the_priority_map->ready_major = mask;
|
||||
the_priority_map->block_major = ~mask;
|
||||
|
||||
mask = _CPU_Priority_Mask( minor );
|
||||
mask = _Priority_Mask( minor );
|
||||
the_priority_map->ready_minor = mask;
|
||||
the_priority_map->block_minor = ~mask;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ STATIC INLINE boolean _ISR_Is_vector_number_valid (
|
||||
unsigned32 vector
|
||||
)
|
||||
{
|
||||
return ( vector < CPU_INTERRUPT_NUMBER_OF_VECTORS );
|
||||
return ( vector <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
|
||||
@@ -78,6 +78,37 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
return ( the_priority % 16 );
|
||||
}
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return (0x8000 >> bit_number);
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return bit_number;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -121,8 +152,8 @@ STATIC INLINE Priority_Control _Priority_Get_highest( void )
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major );
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor );
|
||||
|
||||
return (_CPU_Priority_Bits_index( major ) << 4) +
|
||||
_CPU_Priority_Bits_index( minor );
|
||||
return (_Priority_Bits_index( major ) << 4) +
|
||||
_Priority_Bits_index( minor );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -144,13 +175,13 @@ STATIC INLINE void _Priority_Initialize_information(
|
||||
minor = _Priority_Minor( new_priority );
|
||||
|
||||
the_priority_map->minor =
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(major) ];
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(major) ];
|
||||
|
||||
mask = _CPU_Priority_Mask( major );
|
||||
mask = _Priority_Mask( major );
|
||||
the_priority_map->ready_major = mask;
|
||||
the_priority_map->block_major = ~mask;
|
||||
|
||||
mask = _CPU_Priority_Mask( minor );
|
||||
mask = _Priority_Mask( minor );
|
||||
the_priority_map->ready_minor = mask;
|
||||
the_priority_map->block_minor = ~mask;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#define _ISR_Is_vector_number_valid( _vector ) \
|
||||
( (_vector) < CPU_INTERRUPT_NUMBER_OF_VECTORS )
|
||||
( (_vector) <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
|
||||
@@ -64,6 +64,28 @@
|
||||
|
||||
#define _Priority_Minor( _the_priority ) ( (_the_priority) % 16 )
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
(0x8000 >> _bit_number)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Bits_index( _bit_number ) \
|
||||
(_bit_number)
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -103,8 +125,8 @@
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major ); \
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor ); \
|
||||
\
|
||||
(_high_priority) = (_CPU_Priority_Bits_index( major ) * 16) + \
|
||||
_CPU_Priority_Bits_index( minor ); \
|
||||
(_high_priority) = (_Priority_Bits_index( major ) * 16) + \
|
||||
_Priority_Bits_index( minor ); \
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -124,13 +146,13 @@
|
||||
_minor = _Priority_Minor( (_new_priority) ); \
|
||||
\
|
||||
(_the_priority_map)->minor = \
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(_major) ]; \
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(_major) ]; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _major ); \
|
||||
_mask = _Priority_Mask( _major ); \
|
||||
(_the_priority_map)->ready_major = _mask; \
|
||||
(_the_priority_map)->block_major = ~_mask; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _minor ); \
|
||||
_mask = _Priority_Mask( _minor ); \
|
||||
(_the_priority_map)->ready_minor = _mask; \
|
||||
(_the_priority_map)->block_minor = ~_mask; \
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#define _ISR_Is_vector_number_valid( _vector ) \
|
||||
( (_vector) < CPU_INTERRUPT_NUMBER_OF_VECTORS )
|
||||
( (_vector) <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
|
||||
@@ -64,6 +64,28 @@
|
||||
|
||||
#define _Priority_Minor( _the_priority ) ( (_the_priority) % 16 )
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
(0x8000 >> _bit_number)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Bits_index( _bit_number ) \
|
||||
(_bit_number)
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -103,8 +125,8 @@
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major ); \
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor ); \
|
||||
\
|
||||
(_high_priority) = (_CPU_Priority_Bits_index( major ) * 16) + \
|
||||
_CPU_Priority_Bits_index( minor ); \
|
||||
(_high_priority) = (_Priority_Bits_index( major ) * 16) + \
|
||||
_Priority_Bits_index( minor ); \
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -124,13 +146,13 @@
|
||||
_minor = _Priority_Minor( (_new_priority) ); \
|
||||
\
|
||||
(_the_priority_map)->minor = \
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(_major) ]; \
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(_major) ]; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _major ); \
|
||||
_mask = _Priority_Mask( _major ); \
|
||||
(_the_priority_map)->ready_major = _mask; \
|
||||
(_the_priority_map)->block_major = ~_mask; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _minor ); \
|
||||
_mask = _Priority_Mask( _minor ); \
|
||||
(_the_priority_map)->ready_minor = _mask; \
|
||||
(_the_priority_map)->block_minor = ~_mask; \
|
||||
}
|
||||
|
||||
@@ -805,9 +805,12 @@ void _Thread_Load_environment(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
boolean is_fp = FALSE;
|
||||
|
||||
if ( the_thread->Start.fp_context ) {
|
||||
the_thread->fp_context = the_thread->Start.fp_context;
|
||||
_Context_Initialize_fp( &the_thread->fp_context );
|
||||
is_fp = TRUE;
|
||||
}
|
||||
|
||||
the_thread->is_preemptible = the_thread->Start.is_preemptible;
|
||||
@@ -818,7 +821,8 @@ void _Thread_Load_environment(
|
||||
the_thread->Start.Initial_stack.area,
|
||||
the_thread->Start.Initial_stack.size,
|
||||
the_thread->Start.isr_level,
|
||||
_Thread_Handler
|
||||
_Thread_Handler,
|
||||
is_fp
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
#define __RINGBUF_H__
|
||||
|
||||
#ifndef RINGBUF_QUEUE_LENGTH
|
||||
#define RINGBUF_QUEUE_LENGTH 200
|
||||
#define RINGBUF_QUEUE_LENGTH 128
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char buffer[RINGBUF_QUEUE_LENGTH];
|
||||
int head;
|
||||
int tail;
|
||||
volatile int head;
|
||||
volatile int tail;
|
||||
} Ring_buffer_t;
|
||||
|
||||
#define Ring_buffer_Initialize( _buffer ) \
|
||||
@@ -27,16 +27,27 @@ typedef struct {
|
||||
#define Ring_buffer_Is_empty( _buffer ) \
|
||||
( (_buffer)->head == (_buffer)->tail )
|
||||
|
||||
#define Ring_buffer_Is_full( _buffer ) \
|
||||
( (_buffer)->head == ((_buffer)->tail + 1) % RINGBUF_QUEUE_LENGTH )
|
||||
|
||||
#define Ring_buffer_Add_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->tail = ((_buffer)->tail+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define Ring_buffer_Remove_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->head = ((_buffer)->head+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <rtems.h>
|
||||
#include <bsp.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/score/intthrd.h>
|
||||
#include <rtems/intthrd.h>
|
||||
|
||||
#include <libcsupport.h>
|
||||
|
||||
@@ -244,18 +244,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
if ((stdin_fd = __open("/dev/tty00", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdout_fd = __open("/dev/tty00", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/tty00", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -75,17 +75,6 @@ void Install_clock(
|
||||
atexit( Clock_exit );
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
if ( BSP_Configuration.ticks_per_timeslice ) {
|
||||
@@ -119,6 +108,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -135,7 +125,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -122,18 +122,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -108,17 +108,6 @@ void Install_clock(
|
||||
atexit( Clock_exit );
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
if ( BSP_Configuration.ticks_per_timeslice ) {
|
||||
@@ -161,6 +150,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -177,7 +167,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -129,18 +129,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
/* This is the original command line passed from DOS */
|
||||
|
||||
@@ -60,13 +60,6 @@ void Install_clock(
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
}
|
||||
|
||||
void Clock_exit()
|
||||
{
|
||||
unsigned char *victimer;
|
||||
@@ -105,6 +98,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -121,7 +115,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -124,18 +124,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -97,17 +97,6 @@ void Install_clock(
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0 ;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
rtems_unsigned8 data;
|
||||
@@ -145,6 +134,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -161,7 +151,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -123,18 +123,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -70,17 +70,6 @@ void Install_clock(
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0 ;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
|
||||
@@ -120,6 +109,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -136,7 +126,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -123,18 +123,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -93,17 +93,6 @@ void Install_clock(
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0 ;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
|
||||
@@ -141,6 +130,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -157,7 +147,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -130,18 +130,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -89,7 +89,7 @@ void Install_clock(
|
||||
Clock_isrs = BSP_Configuration.microseconds_per_tick / 1000;
|
||||
|
||||
if ( BSP_Configuration.ticks_per_timeslice ) {
|
||||
/* set_vector( clock_isr, CLOCK_VECTOR, 1 );*/
|
||||
set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
|
||||
m302.reg.trr1 = TRR1_VAL; /* set timer reference register */
|
||||
m302.reg.tmr1 = TMR1_VAL; /* set timer mode register & enable */
|
||||
@@ -102,17 +102,6 @@ void Install_clock(
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
/* (void) set_vector( clock_isr, CLOCK_VECTOR, 1 ); */
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
if ( BSP_Configuration.ticks_per_timeslice ) {
|
||||
@@ -145,6 +134,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -161,7 +151,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -193,7 +193,6 @@ cpy_Bad1: move.l d1,(a0)+
|
||||
|
||||
| move.l #_cnsl_isr,vbase+0x028 | SCC2
|
||||
move.l #timerisr,vbase+0x018 | Timer ISR
|
||||
move.l #RTC_ISR,vbase+0x024 | Real Time Clock ISR
|
||||
|
||||
|
|
||||
| zero out uninitialized data area
|
||||
@@ -236,14 +235,6 @@ loop: movel d0,a1@+ | to zero out uninitialized
|
||||
Bad: bra Bad
|
||||
|
||||
nop
|
||||
RTC_ISR:
|
||||
movem.l d0-d1/a0-a1,a7@- | save d0-d1,a0-a1
|
||||
addql #1,_ISR_Nest_level | one nest level deeper
|
||||
addql #1,_Thread_Dispatch_disable_level
|
||||
| disable multitasking
|
||||
|
||||
jbsr Clock_isr | invoke the user ISR
|
||||
jmp _ISR_Exit
|
||||
END_CODE
|
||||
|
||||
|
||||
|
||||
@@ -193,7 +193,6 @@ cpy_Bad1: move.l d1,(a0)+
|
||||
|
||||
| move.l #_cnsl_isr,vbase+0x028 | SCC2
|
||||
move.l #timerisr,vbase+0x018 | Timer ISR
|
||||
move.l #RTC_ISR,vbase+0x024 | Real Time Clock ISR
|
||||
|
||||
|
|
||||
| zero out uninitialized data area
|
||||
@@ -236,14 +235,6 @@ loop: movel d0,a1@+ | to zero out uninitialized
|
||||
Bad: bra Bad
|
||||
|
||||
nop
|
||||
RTC_ISR:
|
||||
movem.l d0-d1/a0-a1,a7@- | save d0-d1,a0-a1
|
||||
addql #1,_ISR_Nest_level | one nest level deeper
|
||||
addql #1,_Thread_Dispatch_disable_level
|
||||
| disable multitasking
|
||||
|
||||
jbsr Clock_isr | invoke the user ISR
|
||||
jmp _ISR_Exit
|
||||
END_CODE
|
||||
|
||||
|
||||
|
||||
@@ -130,18 +130,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -130,16 +130,6 @@ rtems_isr_entry clock_isr;
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock( clock_isr )
|
||||
rtems_isr_entry clock_isr;
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0 ;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
/* The following was added for debugging purposes */
|
||||
void Clock_exit( void )
|
||||
{
|
||||
@@ -181,6 +171,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -197,7 +188,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*#########################################################
|
||||
#
|
||||
|
||||
@@ -131,18 +131,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -108,17 +108,6 @@ void Install_clock(
|
||||
|
||||
}
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
volatile struct z8036_map *timer;
|
||||
@@ -157,6 +146,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -173,7 +163,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -124,18 +124,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -89,15 +89,6 @@ void Install_clock(rtems_isr_entry clock_isr )
|
||||
}
|
||||
}
|
||||
|
||||
void ReInstall_clock(rtems_isr_entry clock_isr)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
void Clock_exit( void )
|
||||
{
|
||||
/* Dummy for now. See other m68k BSP's for code examples */
|
||||
@@ -127,6 +118,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -143,7 +135,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -130,18 +130,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -105,7 +105,7 @@ void Install_clock(
|
||||
*/
|
||||
|
||||
if ( BSP_Configuration.ticks_per_timeslice ) {
|
||||
Old_ticker = ( rtems_isr_entry ) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
Old_ticker = (rtems_isr_entry) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
/*
|
||||
* Hardware specific initialize goes here
|
||||
*/
|
||||
@@ -120,30 +120,6 @@ void Install_clock(
|
||||
atexit( Clock_exit );
|
||||
}
|
||||
|
||||
/*
|
||||
* Reinstall_clock
|
||||
*
|
||||
* Install a clock tick handler without reprogramming the chip. This
|
||||
* is used by the polling shared memory device driver.
|
||||
*/
|
||||
|
||||
void ReInstall_clock(
|
||||
rtems_isr_entry clock_isr
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0;
|
||||
|
||||
/*
|
||||
* Disable interrupts and install the clock ISR vector using the
|
||||
* BSP dependent set_vector routine. In the below example, the clock
|
||||
* ISR is on vector 4 and is an RTEMS interrupt.
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( clock_isr, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up before the application exits
|
||||
*/
|
||||
@@ -188,6 +164,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -204,7 +181,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, CLOCK_VECTOR, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -131,18 +131,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int bsp_start(
|
||||
|
||||
@@ -149,18 +149,21 @@ void
|
||||
bsp_postdriver_hook(void)
|
||||
{
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
}
|
||||
|
||||
int main(
|
||||
|
||||
@@ -31,30 +31,18 @@ rtems_unsigned32 Clock_driver_vector;
|
||||
rtems_device_major_number rtems_clock_major = ~0;
|
||||
rtems_device_minor_number rtems_clock_minor;
|
||||
|
||||
void
|
||||
Install_clock(rtems_isr_entry clock_isr)
|
||||
void Install_clock(rtems_isr_entry clock_isr)
|
||||
{
|
||||
Clock_driver_ticks = 0;
|
||||
|
||||
(void)set_vector(clock_isr, Clock_driver_vector, 1);
|
||||
(void) set_vector( clock_isr, Clock_driver_vector, 1 );
|
||||
|
||||
_CPU_Start_clock( BSP_Configuration.microseconds_per_tick );
|
||||
|
||||
atexit(Clock_exit);
|
||||
}
|
||||
|
||||
void
|
||||
ReInstall_clock(rtems_isr_entry new_clock_isr)
|
||||
{
|
||||
rtems_unsigned32 isrlevel = 0;
|
||||
|
||||
rtems_interrupt_disable(isrlevel);
|
||||
(void)set_vector(new_clock_isr, Clock_driver_vector, 1);
|
||||
rtems_interrupt_enable(isrlevel);
|
||||
}
|
||||
|
||||
void
|
||||
Clock_isr(int vector)
|
||||
void Clock_isr(int vector)
|
||||
{
|
||||
Clock_driver_ticks++;
|
||||
rtems_clock_tick();
|
||||
@@ -65,16 +53,14 @@ Clock_isr(int vector)
|
||||
* Remove the clock signal
|
||||
*/
|
||||
|
||||
void
|
||||
Clock_exit(void)
|
||||
void Clock_exit(void)
|
||||
{
|
||||
_CPU_Stop_clock();
|
||||
|
||||
(void)set_vector(0, Clock_driver_vector, 1);
|
||||
(void) set_vector( 0, Clock_driver_vector, 1 );
|
||||
}
|
||||
|
||||
rtems_device_driver
|
||||
Clock_initialize(
|
||||
rtems_device_driver Clock_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *pargp
|
||||
@@ -99,6 +85,7 @@ rtems_device_driver Clock_control(
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
rtems_unsigned32 isrlevel;
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
if (args == 0)
|
||||
@@ -115,7 +102,9 @@ rtems_device_driver Clock_control(
|
||||
}
|
||||
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
||||
{
|
||||
ReInstall_clock(args->buffer);
|
||||
rtems_interrupt_disable( isrlevel );
|
||||
(void) set_vector( args->buffer, Clock_driver_vector, 1 );
|
||||
rtems_interrupt_enable( isrlevel );
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -182,18 +182,21 @@ bsp_postdriver_hook(void)
|
||||
{
|
||||
#if 0
|
||||
int stdin_fd, stdout_fd, stderr_fd;
|
||||
int error_code;
|
||||
|
||||
error_code = 'S' << 24 | 'T' << 16;
|
||||
|
||||
if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD0');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '0' );
|
||||
|
||||
if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD1');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '1' );
|
||||
|
||||
if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1)
|
||||
rtems_fatal_error_occurred('STD2');
|
||||
rtems_fatal_error_occurred( error_code | 'D' << 8 | '2' );
|
||||
|
||||
if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2))
|
||||
rtems_fatal_error_occurred('STIO');
|
||||
rtems_fatal_error_occurred( error_code | 'I' << 8 | 'O' );
|
||||
#endif
|
||||
|
||||
#if defined(MALLOC_STATS)
|
||||
|
||||
503
c/src/lib/libcpu/sparc/include/erc32.h
Normal file
503
c/src/lib/libcpu/sparc/include/erc32.h
Normal file
@@ -0,0 +1,503 @@
|
||||
/* erc32.h
|
||||
*
|
||||
* This include file contains information pertaining to the ERC32.
|
||||
* The ERC32 is a custom SPARC V7 implementation based on the Cypress
|
||||
* 601/602 chipset. This CPU has a number of on-board peripherals and
|
||||
* was developed by the European Space Agency to target space applications.
|
||||
*
|
||||
* NOTE: Other than where absolutely required, this version currently
|
||||
* supports only the peripherals and bits used by the basic board
|
||||
* support package. This includes at least significant pieces of
|
||||
* the following items:
|
||||
*
|
||||
* + UART Channels A and B
|
||||
* + General Purpose Timer
|
||||
* + Real Time Clock
|
||||
* + Watchdog Timer (so it can be disabled)
|
||||
* + Control Register (so powerdown mode can be enabled)
|
||||
* + Memory Control Register
|
||||
* + Interrupt Control
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_ERC32_h
|
||||
#define _INCLUDE_ERC32_h
|
||||
|
||||
#include <rtems/score/sparc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt Sources
|
||||
*
|
||||
* The interrupt source numbers directly map to the trap type and to
|
||||
* the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask,
|
||||
* and the Interrupt Pending Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_INTERRUPT_MASKED_ERRORS 1
|
||||
#define ERC32_INTERRUPT_EXTERNAL_1 2
|
||||
#define ERC32_INTERRUPT_EXTERNAL_2 3
|
||||
#define ERC32_INTERRUPT_UART_A_RX_TX 4
|
||||
#define ERC32_INTERRUPT_UART_B_RX_TX 5
|
||||
#define ERC32_INTERRUPT_CORRECTABLE_MEMORY_ERROR 6
|
||||
#define ERC32_INTERRUPT_UART_ERROR 7
|
||||
#define ERC32_INTERRUPT_DMA_ACCESS_ERROR 8
|
||||
#define ERC32_INTERRUPT_DMA_TIMEOUT 9
|
||||
#define ERC32_INTERRUPT_EXTERNAL_3 10
|
||||
#define ERC32_INTERRUPT_EXTERNAL_4 11
|
||||
#define ERC32_INTERRUPT_GENERAL_PURPOSE_TIMER 12
|
||||
#define ERC32_INTERRUPT_REAL_TIME_CLOCK 13
|
||||
#define ERC32_INTERRUPT_EXTERNAL_5 14
|
||||
#define ERC32_INTERRUPT_WATCHDOG_TIMEOUT 15
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* Trap Types for on-chip peripherals
|
||||
*
|
||||
* Source: Table 8 - Interrupt Trap Type and Default Priority Assignments
|
||||
*
|
||||
* NOTE: The priority level for each source corresponds to the least
|
||||
* significant nibble of the trap type.
|
||||
*/
|
||||
|
||||
#define ERC32_TRAP_TYPE( _source ) SPARC_ASYNCHRONOUS_TRAP((_source) + 0x10)
|
||||
|
||||
#define ERC32_TRAP_SOURCE( _trap ) ((_trap) - 0x10)
|
||||
|
||||
#define ERC32_Is_MEC_Trap( _trap ) \
|
||||
( (_trap) >= ERC32_TRAP_TYPE( ERC32_INTERRUPT_MASKED_ERRORS ) && \
|
||||
(_trap) <= ERC32_TRAP_TYPE( ERC32_INTERRUPT_WATCHDOG_TIMEOUT ) )
|
||||
|
||||
/*
|
||||
* Structure for ERC32 memory mapped registers.
|
||||
*
|
||||
* Source: Section 3.25.2 - Register Address Map
|
||||
*
|
||||
* NOTE: There is only one of these structures per CPU, its base address
|
||||
* is 0x01f80000, and the variable MEC is placed there by the
|
||||
* linkcmds file.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned32 Control; /* offset 0x00 */
|
||||
volatile unsigned32 Software_Reset; /* offset 0x04 */
|
||||
volatile unsigned32 Power_Down; /* offset 0x08 */
|
||||
volatile unsigned32 Unimplemented_0; /* offset 0x0c */
|
||||
volatile unsigned32 Memory_Configuration; /* offset 0x10 */
|
||||
volatile unsigned32 IO_Configuration; /* offset 0x14 */
|
||||
volatile unsigned32 Wait_State_Configuration; /* offset 0x18 */
|
||||
volatile unsigned32 Unimplemented_1; /* offset 0x1c */
|
||||
volatile unsigned32 Memory_Access_0; /* offset 0x20 */
|
||||
volatile unsigned32 Memory_Access_1; /* offset 0x24 */
|
||||
volatile unsigned32 Unimplemented_2[ 7 ]; /* offset 0x28 */
|
||||
volatile unsigned32 Interrupt_Shape; /* offset 0x44 */
|
||||
volatile unsigned32 Interrupt_Pending; /* offset 0x48 */
|
||||
volatile unsigned32 Interrupt_Mask; /* offset 0x4c */
|
||||
volatile unsigned32 Interrupt_Clear; /* offset 0x50 */
|
||||
volatile unsigned32 Interrupt_Force; /* offset 0x54 */
|
||||
volatile unsigned32 Unimplemented_3[ 2 ]; /* offset 0x58 */
|
||||
/* offset 0x60 */
|
||||
volatile unsigned32 Watchdog_Program_and_Timeout_Acknowledge;
|
||||
volatile unsigned32 Watchdog_Trap_Door_Set; /* offset 0x64 */
|
||||
volatile unsigned32 Unimplemented_4[ 6 ]; /* offset 0x68 */
|
||||
volatile unsigned32 Real_Time_Clock_Counter; /* offset 0x80 */
|
||||
volatile unsigned32 Real_Time_Clock_Scalar; /* offset 0x84 */
|
||||
volatile unsigned32 General_Purpose_Timer_Counter; /* offset 0x88 */
|
||||
volatile unsigned32 General_Purpose_Timer_Scalar; /* offset 0x8c */
|
||||
volatile unsigned32 Unimplemented_5[ 2 ]; /* offset 0x90 */
|
||||
volatile unsigned32 Timer_Control; /* offset 0x98 */
|
||||
volatile unsigned32 Unimplemented_6; /* offset 0x9c */
|
||||
volatile unsigned32 System_Fault_Status; /* offset 0xa0 */
|
||||
volatile unsigned32 First_Failing_Address; /* offset 0xa4 */
|
||||
volatile unsigned32 First_Failing_Data; /* offset 0xa8 */
|
||||
volatile unsigned32 First_Failing_Syndrome_and_Check_Bits;/* offset 0xac */
|
||||
volatile unsigned32 Error_and_Reset_Status; /* offset 0xb0 */
|
||||
volatile unsigned32 Error_Mask; /* offset 0xb4 */
|
||||
volatile unsigned32 Unimplemented_7[ 2 ]; /* offset 0xb8 */
|
||||
volatile unsigned32 Debug_Control; /* offset 0xc0 */
|
||||
volatile unsigned32 Breakpoint; /* offset 0xc4 */
|
||||
volatile unsigned32 Watchpoint; /* offset 0xc8 */
|
||||
volatile unsigned32 Unimplemented_8; /* offset 0xcc */
|
||||
volatile unsigned32 Test_Control; /* offset 0xd0 */
|
||||
volatile unsigned32 Test_Data; /* offset 0xd4 */
|
||||
volatile unsigned32 Unimplemented_9[ 2 ]; /* offset 0xd8 */
|
||||
volatile unsigned32 UART_Channel_A; /* offset 0xe0 */
|
||||
volatile unsigned32 UART_Channel_B; /* offset 0xe4 */
|
||||
volatile unsigned32 UART_Status; /* offset 0xe8 */
|
||||
} ERC32_Register_Map;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following constants are intended to be used ONLY in assembly
|
||||
* language files.
|
||||
*
|
||||
* NOTE: The intended style of usage is to load the address of MEC
|
||||
* into a register and then use these as displacements from
|
||||
* that register.
|
||||
*/
|
||||
|
||||
#ifdef ASM
|
||||
|
||||
#define ERC32_MEC_CONTROL_OFFSET 0x00
|
||||
#define ERC32_MEC_SOFTWARE_RESET_OFFSET 0x04
|
||||
#define ERC32_MEC_POWER_DOWN_OFFSET 0x08
|
||||
#define ERC32_MEC_UNIMPLEMENTED_0_OFFSET 0x0C
|
||||
#define ERC32_MEC_MEMORY_CONFIGURATION_OFFSET 0x10
|
||||
#define ERC32_MEC_IO_CONFIGURATION_OFFSET 0x14
|
||||
#define ERC32_MEC_WAIT_STATE_CONFIGURATION_OFFSET 0x18
|
||||
#define ERC32_MEC_UNIMPLEMENTED_1_OFFSET 0x1C
|
||||
#define ERC32_MEC_MEMORY_ACCESS_0_OFFSET 0x20
|
||||
#define ERC32_MEC_MEMORY_ACCESS_1_OFFSET 0x24
|
||||
#define ERC32_MEC_UNIMPLEMENTED_2_OFFSET 0x28
|
||||
#define ERC32_MEC_INTERRUPT_SHAPE_OFFSET 0x44
|
||||
#define ERC32_MEC_INTERRUPT_PENDING_OFFSET 0x48
|
||||
#define ERC32_MEC_INTERRUPT_MASK_OFFSET 0x4C
|
||||
#define ERC32_MEC_INTERRUPT_CLEAR_OFFSET 0x50
|
||||
#define ERC32_MEC_INTERRUPT_FORCE_OFFSET 0x54
|
||||
#define ERC32_MEC_UNIMPLEMENTED_3_OFFSET 0x58
|
||||
#define ERC32_MEC_WATCHDOG_PROGRAM_AND_TIMEOUT_ACKNOWLEDGE_OFFSET 0x60
|
||||
#define ERC32_MEC_WATCHDOG_TRAP_DOOR_SET_OFFSET 0x64
|
||||
#define ERC32_MEC_UNIMPLEMENTED_4_OFFSET 0x6C
|
||||
#define ERC32_MEC_REAL_TIME_CLOCK_COUNTER_OFFSET 0x80
|
||||
#define ERC32_MEC_REAL_TIME_CLOCK_SCALAR_OFFSET 0x84
|
||||
#define ERC32_MEC_GENERAL_PURPOSE_TIMER_COUNTER_OFFSET 0x88
|
||||
#define ERC32_MEC_GENERAL_PURPOSE_TIMER_SCALAR_OFFSET 0x8C
|
||||
#define ERC32_MEC_UNIMPLEMENTED_5_OFFSET 0x90
|
||||
#define ERC32_MEC_TIMER_CONTROL_OFFSET 0x98
|
||||
#define ERC32_MEC_UNIMPLEMENTED_6_OFFSET 0x9C
|
||||
#define ERC32_MEC_SYSTEM_FAULT_STATUS_OFFSET 0xA0
|
||||
#define ERC32_MEC_FIRST_FAILING_ADDRESS_OFFSET 0xA4
|
||||
#define ERC32_MEC_FIRST_FAILING_DATA_OFFSET 0xA8
|
||||
#define ERC32_MEC_FIRST_FAILING_SYNDROME_AND_CHECK_BITS_OFFSET 0xAC
|
||||
#define ERC32_MEC_ERROR_AND_RESET_STATUS_OFFSET 0xB0
|
||||
#define ERC32_MEC_ERROR_MASK_OFFSET 0xB4
|
||||
#define ERC32_MEC_UNIMPLEMENTED_7_OFFSET 0xB8
|
||||
#define ERC32_MEC_DEBUG_CONTROL_OFFSET 0xC0
|
||||
#define ERC32_MEC_BREAKPOINT_OFFSET 0xC4
|
||||
#define ERC32_MEC_WATCHPOINT_OFFSET 0xC8
|
||||
#define ERC32_MEC_UNIMPLEMENTED_8_OFFSET 0xCC
|
||||
#define ERC32_MEC_TEST_CONTROL_OFFSET 0xD0
|
||||
#define ERC32_MEC_TEST_DATA_OFFSET 0xD4
|
||||
#define ERC32_MEC_UNIMPLEMENTED_9_OFFSET 0xD8
|
||||
#define ERC32_MEC_UART_CHANNEL_A_OFFSET 0xE0
|
||||
#define ERC32_MEC_UART_CHANNEL_B_OFFSET 0xE4
|
||||
#define ERC32_MEC_UART_STATUS_OFFSET 0xE8
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Configuration Register.
|
||||
*/
|
||||
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_MASK 0x00000001
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_ALLOWED 0x00000001
|
||||
#define ERC32_CONFIGURATION_POWER_DOWN_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_MASK 0x00000002
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_ALLOWED 0x00000002
|
||||
#define ERC32_CONFIGURATION_SOFTWARE_RESET_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_MASK 0x00000004
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_ENABLED 0x00000004
|
||||
#define ERC32_CONFIGURATION_BUS_TIMEOUT_DISABLED 0x00000000
|
||||
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_MASK 0x00000008
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_ENABLED 0x00000008
|
||||
#define ERC32_CONFIGURATION_ACCESS_PROTECTION_DISABLED 0x00000000
|
||||
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Memory Configuration Register.
|
||||
*/
|
||||
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_MASK 0x00001C00
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_256K ( 0 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_512K ( 1 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_1MB ( 2 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_2MB ( 3 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_4MB ( 4 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_8MB ( 5 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_16MB ( 6 << 10 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_32MB ( 7 << 10 )
|
||||
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_MASK 0x001C0000
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_4K ( 0 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_8K ( 1 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_16K ( 2 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_32K ( 3 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_64K ( 4 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_128K ( 5 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_256K ( 6 << 18 )
|
||||
#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_512K ( 7 << 18 )
|
||||
|
||||
/*
|
||||
* The following defines the bits in the Timer Control Register.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_TIMER_CONTROL_GCR 0x00000001 /* 1 = reload at 0 */
|
||||
/* 0 = stop at 0 */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GCL 0x00000002 /* 1 = load and start */
|
||||
/* 0 = no function */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GSE 0x00000004 /* 1 = enable counting */
|
||||
/* 0 = hold scalar and counter */
|
||||
#define ERC32_MEC_TIMER_CONTROL_GSL 0x00000008 /* 1 = load scalar and start */
|
||||
/* 0 = no function */
|
||||
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCCR 0x00000100 /* 1 = reload at 0 */
|
||||
/* 0 = stop at 0 */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCCL 0x00000200 /* 1 = load and start */
|
||||
/* 0 = no function */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCSE 0x00000400 /* 1 = enable counting */
|
||||
/* 0 = hold scalar and counter */
|
||||
#define ERC32_MEC_TIMER_CONTROL_RTCSL 0x00000800 /* 1 = load scalar and start */
|
||||
/* 0 = no function */
|
||||
|
||||
/*
|
||||
* The following defines the bits in the UART Control Registers.
|
||||
*
|
||||
* NOTE: Same bits in UART channels A and B.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_UART_CONTROL_RTD 0x000000FF /* RX/TX data */
|
||||
#define ERC32_MEC_UART_CONTROL_DR 0x00000100 /* RX Data Ready */
|
||||
#define ERC32_MEC_UART_CONTROL_TSE 0x00000200 /* TX Send Empty */
|
||||
/* (i.e. no data to send) */
|
||||
#define ERC32_MEC_UART_CONTROL_THE 0x00000400 /* TX Hold Empty */
|
||||
/* (i.e. ready to load) */
|
||||
|
||||
/*
|
||||
* The following defines the bits in the MEC UART Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DR 0x00000001 /* Data Ready */
|
||||
#define ERC32_MEC_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
|
||||
#define ERC32_MEC_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
|
||||
#define ERC32_MEC_UART_STATUS_FE 0x00000010 /* RX Framing Error */
|
||||
#define ERC32_MEC_UART_STATUS_PE 0x00000020 /* RX Parity Error */
|
||||
#define ERC32_MEC_UART_STATUS_OE 0x00000040 /* RX Overrun Error */
|
||||
#define ERC32_MEC_UART_STATUS_CU 0x00000080 /* Clear Errors */
|
||||
#define ERC32_MEC_UART_STATUS_TXE 0x00000006 /* TX Empty */
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DRA (ERC32_MEC_UART_STATUS_DR << 0)
|
||||
#define ERC32_MEC_UART_STATUS_TSEA (ERC32_MEC_UART_STATUS_TSE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_THEA (ERC32_MEC_UART_STATUS_THE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_FEA (ERC32_MEC_UART_STATUS_FE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_PEA (ERC32_MEC_UART_STATUS_PE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_OEA (ERC32_MEC_UART_STATUS_OE << 0)
|
||||
#define ERC32_MEC_UART_STATUS_CUA (ERC32_MEC_UART_STATUS_CU << 0)
|
||||
#define ERC32_MEC_UART_STATUS_TXEA (ERC32_MEC_UART_STATUS_TXE << 0)
|
||||
|
||||
#define ERC32_MEC_UART_STATUS_DRB (ERC32_MEC_UART_STATUS_DR << 16)
|
||||
#define ERC32_MEC_UART_STATUS_TSEB (ERC32_MEC_UART_STATUS_TSE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_THEB (ERC32_MEC_UART_STATUS_THE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_FEB (ERC32_MEC_UART_STATUS_FE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_PEB (ERC32_MEC_UART_STATUS_PE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_OEB (ERC32_MEC_UART_STATUS_OE << 16)
|
||||
#define ERC32_MEC_UART_STATUS_CUB (ERC32_MEC_UART_STATUS_CU << 16)
|
||||
#define ERC32_MEC_UART_STATUS_TXEB (ERC32_MEC_UART_STATUS_TXE << 16)
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/*
|
||||
* This is used to manipulate the on-chip registers.
|
||||
*
|
||||
* The following symbol must be defined in the linkcmds file and point
|
||||
* to the correct location.
|
||||
*/
|
||||
|
||||
extern ERC32_Register_Map ERC32_MEC;
|
||||
|
||||
/*
|
||||
* Macros to manipulate the Interrupt Clear, Interrupt Force, Interrupt Mask,
|
||||
* and the Interrupt Pending Registers.
|
||||
*
|
||||
* NOTE: For operations which are not atomic, this code disables interrupts
|
||||
* to guarantee there are no intervening accesses to the same register.
|
||||
* The operations which read the register, modify the value and then
|
||||
* store the result back are vulnerable.
|
||||
*/
|
||||
|
||||
#define ERC32_Clear_interrupt( _source ) \
|
||||
do { \
|
||||
ERC32_MEC.Interrupt_Clear = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Force_interrupt( _source ) \
|
||||
do { \
|
||||
ERC32_MEC.Interrupt_Force = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Is_interrupt_pending( _source ) \
|
||||
(ERC32_MEC.Interrupt_Pending & (1 << (_source)))
|
||||
|
||||
#define ERC32_Is_interrupt_masked( _source ) \
|
||||
(ERC32_MEC.Interrupt_Masked & (1 << (_source)))
|
||||
|
||||
#define ERC32_Mask_interrupt( _source ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask |= (1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Unmask_interrupt( _source ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask &= ~(1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Disable_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _mask = 1 << (_source); \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
(_previous) = ERC32_MEC.Interrupt_Mask; \
|
||||
ERC32_MEC.Interrupt_Mask = _previous | _mask; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
(_previous) &= ~_mask; \
|
||||
} while (0)
|
||||
|
||||
#define ERC32_Restore_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _mask = 1 << (_source); \
|
||||
\
|
||||
sparc_disable_interrupts( _level ); \
|
||||
ERC32_MEC.Interrupt_Mask = \
|
||||
(ERC32_MEC.Interrupt_Mask & ~_mask) | (_previous); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The following macros attempt to hide the fact that the General Purpose
|
||||
* Timer and Real Time Clock Timer share the Timer Control Register. Because
|
||||
* the Timer Control Register is write only, we must mirror it in software
|
||||
* and insure that writes to one timer do not alter the current settings
|
||||
* and status of the other timer.
|
||||
*
|
||||
* This code promotes the view that the two timers are completely independent.
|
||||
* By exclusively using the routines below to access the Timer Control
|
||||
* Register, the application can view the system as having a General Purpose
|
||||
* Timer Control Register and a Real Time Clock Timer Control Register
|
||||
* rather than the single shared value.
|
||||
*
|
||||
* Each logical timer control register is organized as follows:
|
||||
*
|
||||
* D0 - Counter Reload
|
||||
* 1 = reload counter at zero and restart
|
||||
* 0 = stop counter at zero
|
||||
*
|
||||
* D1 - Counter Load
|
||||
* 1 = load counter with preset value and restart
|
||||
* 0 = no function
|
||||
*
|
||||
* D2 - Enable
|
||||
* 1 = enable counting
|
||||
* 0 = hold scaler and counter
|
||||
*
|
||||
* D2 - Scaler Load
|
||||
* 1 = load scalar with preset value and restart
|
||||
* 0 = no function
|
||||
*
|
||||
* To insure the management of the mirror is atomic, we disable interrupts
|
||||
* around updates.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO 0x00000001
|
||||
#define ERC32_MEC_TIMER_COUNTER_STOP_AT_ZERO 0x00000000
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER 0x00000002
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING 0x00000004
|
||||
#define ERC32_MEC_TIMER_COUNTER_DISABLE_COUNTING 0x00000000
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_LOAD_SCALER 0x00000008
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_RELOAD_MASK 0x00000001
|
||||
#define ERC32_MEC_TIMER_COUNTER_ENABLE_MASK 0x00000004
|
||||
|
||||
#define ERC32_MEC_TIMER_COUNTER_DEFINED_MASK 0x0000000F
|
||||
#define ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000005
|
||||
|
||||
extern unsigned32 _ERC32_MEC_Timer_Control_Mirror;
|
||||
|
||||
/*
|
||||
* This macros manipulate the General Purpose Timer portion of the
|
||||
* Timer Control register and promote the view that there are actually
|
||||
* two independent Timer Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_Set_General_Purpose_Timer_Control( _value ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _control; \
|
||||
unsigned32 __value; \
|
||||
\
|
||||
__value = ((_value) & 0x0f); \
|
||||
sparc_disable_interrupts( _level ); \
|
||||
_control = _ERC32_MEC_Timer_Control_Mirror; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK << 8; \
|
||||
_ERC32_MEC_Timer_Control_Mirror = _control | _value; \
|
||||
_control &= (ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK << 8); \
|
||||
_control |= __value; \
|
||||
/* printf( "GPT 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
|
||||
ERC32_MEC.Timer_Control = _control; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define ERC32_MEC_Get_General_Purpose_Timer_Control( _value ) \
|
||||
do { \
|
||||
(_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
|
||||
} while ( 0 )
|
||||
|
||||
/*
|
||||
* This macros manipulate the Real Timer Clock Timer portion of the
|
||||
* Timer Control register and promote the view that there are actually
|
||||
* two independent Timer Control Registers.
|
||||
*/
|
||||
|
||||
#define ERC32_MEC_Set_Real_Time_Clock_Timer_Control( _value ) \
|
||||
do { \
|
||||
unsigned32 _level; \
|
||||
unsigned32 _control; \
|
||||
unsigned32 __value; \
|
||||
\
|
||||
__value = ((_value) & 0x0f) << 8; \
|
||||
sparc_disable_interrupts( _level ); \
|
||||
_control = _ERC32_MEC_Timer_Control_Mirror; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK; \
|
||||
_ERC32_MEC_Timer_Control_Mirror = _control | _value; \
|
||||
_control &= ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK; \
|
||||
_control |= __value; \
|
||||
/* printf( "RTC 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
|
||||
ERC32_MEC.Timer_Control = _control; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define ERC32_MEC_Get_Real_Time_Clock_Timer_Control( _value ) \
|
||||
do { \
|
||||
(_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_INCLUDE_ERC32_h */
|
||||
/* end of include file */
|
||||
|
||||
@@ -30,8 +30,8 @@ rtems_task Task_1(
|
||||
rtems_mode previous_mode;
|
||||
rtems_time_of_day time;
|
||||
rtems_status_code status;
|
||||
rtems_unsigned32 start;
|
||||
rtems_unsigned32 end;
|
||||
rtems_unsigned32 start_time;
|
||||
rtems_unsigned32 end_time;
|
||||
|
||||
puts( "TA1 - rtems_task_suspend - on Task 2" );
|
||||
status = rtems_task_suspend( Task_id[ 2 ] );
|
||||
@@ -41,16 +41,16 @@ rtems_task Task_1(
|
||||
status = rtems_task_suspend( Task_id[ 3 ] );
|
||||
directive_failed( status, "rtems_task_suspend of TA3" );
|
||||
|
||||
status = rtems_clock_get( RTEMS_CLOCK_GET_SECONDS_SINCE_EPOCH, &start );
|
||||
status = rtems_clock_get( RTEMS_CLOCK_GET_SECONDS_SINCE_EPOCH, &start_time );
|
||||
directive_failed( status, "rtems_clock_get" );
|
||||
|
||||
puts( "TA1 - killing time" );
|
||||
|
||||
for ( ; ; ) {
|
||||
status = rtems_clock_get( RTEMS_CLOCK_GET_SECONDS_SINCE_EPOCH, &end );
|
||||
status = rtems_clock_get( RTEMS_CLOCK_GET_SECONDS_SINCE_EPOCH, &end_time );
|
||||
directive_failed( status, "rtems_clock_get" );
|
||||
|
||||
if ( end > (start + 2) )
|
||||
if ( end_time > (start_time + 2) )
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,11 @@ void Screen9()
|
||||
rtems_status_code status;
|
||||
rtems_isr_entry old_service_routine;
|
||||
|
||||
status = rtems_interrupt_catch( Service_routine, 500, &old_service_routine );
|
||||
status = rtems_interrupt_catch(
|
||||
Service_routine,
|
||||
ISR_INTERRUPT_MAXIMUM_VECTOR_NUMBER + 10,
|
||||
&old_service_routine
|
||||
);
|
||||
fatal_directive_status(
|
||||
status,
|
||||
RTEMS_INVALID_NUMBER,
|
||||
|
||||
@@ -11,7 +11,7 @@ TA1 - rtems_event_receive - waiting with 10 second timeout on RTEMS_EVENT_14
|
||||
TA2 - RTEMS_EVENT_17 or RTEMS_EVENT_18 received - eventout => 00040000
|
||||
TA2 - rtems_event_send - send RTEMS_EVENT_14 to TA1
|
||||
TA2 - rtems_clock_set - 08:15:00 02/12/1988
|
||||
TA2 - rtems_event_send - sending RTEMS_EVENT_10 to self after 5 seconds
|
||||
TA2 - rtems_event_send - sending RTEMS_EVENT_10 to self after 4 seconds
|
||||
TA2 - rtems_event_receive - waiting forever on RTEMS_EVENT_10
|
||||
TA1 - RTEMS_EVENT_14 received - eventout => 00004000
|
||||
TA1 - rtems_event_send - send RTEMS_EVENT_19 to TA2
|
||||
|
||||
@@ -73,9 +73,9 @@ rtems_task Task_2(
|
||||
status = rtems_clock_set( &time );
|
||||
directive_failed( status, "TA2 rtems_clock_set" );
|
||||
|
||||
time.second += 5;
|
||||
time.second += 4;
|
||||
puts(
|
||||
"TA2 - rtems_event_send - sending RTEMS_EVENT_10 to self after 5 seconds"
|
||||
"TA2 - rtems_event_send - sending RTEMS_EVENT_10 to self after 4 seconds"
|
||||
);
|
||||
status = rtems_timer_fire_when(
|
||||
Timer_id[ 5 ],
|
||||
@@ -83,7 +83,7 @@ rtems_task Task_2(
|
||||
TA2_send_10_to_self,
|
||||
NULL
|
||||
);
|
||||
directive_failed( status, "rtems_timer_fire_when after 5 seconds" );
|
||||
directive_failed( status, "rtems_timer_fire_when after 4 seconds" );
|
||||
|
||||
puts( "TA2 - rtems_event_receive - waiting forever on RTEMS_EVENT_10" );
|
||||
status = rtems_event_receive(
|
||||
|
||||
@@ -57,6 +57,7 @@ rtems_task Task5(
|
||||
#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_TEST_NEEDS_CLOCK_DRIVER
|
||||
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES 10
|
||||
#define CONFIGURE_TICKS_PER_TIMESLICE 100
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ rtems_task Task_1(
|
||||
|
||||
#define CONFIGURE_SPTEST
|
||||
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
||||
|
||||
#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_TEST_NEEDS_CLOCK_DRIVER
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ rtems_task Init(
|
||||
status = rtems_task_create(
|
||||
Task_name[ index ],
|
||||
Priorities[ index ],
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_MINIMUM_STACK_SIZE * 4,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&Task_id[ index ]
|
||||
|
||||
@@ -52,7 +52,7 @@ rtems_task Init(
|
||||
status = rtems_task_create(
|
||||
Task_name[ index ],
|
||||
1,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_MINIMUM_STACK_SIZE * 2,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&Task_id[ index ]
|
||||
|
||||
@@ -36,8 +36,12 @@ rtems_task Init(
|
||||
|
||||
setvbuf(stdout, 0, _IONBF, 0);
|
||||
|
||||
do {
|
||||
puts( "\n*** RTEMS SIZE PROGRAM ***" );
|
||||
size_rtems( 1 );
|
||||
puts( "*** END OF RTEMS SIZE PROGRAM ***" );
|
||||
exit( 0 );
|
||||
#if 0
|
||||
do {
|
||||
printf( "\n\nPlease select program mode:\n" );
|
||||
printf( " 1) Print Formulas\n" );
|
||||
printf( " 2) Determine Workspace Size\n" );
|
||||
@@ -52,4 +56,5 @@ rtems_task Init(
|
||||
default: continue;
|
||||
}
|
||||
} while ( FOREVER );
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -390,6 +390,22 @@ uninitialized += (sizeof _CPU_Interrupt_stack_low) +
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef sparc
|
||||
|
||||
/* cpu.h */
|
||||
uninitialized += (sizeof _CPU_Interrupt_stack_low) +
|
||||
(sizeof _CPU_Interrupt_stack_high) +
|
||||
(sizeof _CPU_Null_fp_context) +
|
||||
(sizeof _CPU_Trap_Table_area);
|
||||
|
||||
#ifdef erc32
|
||||
uninitialized += (sizeof _ERC32_MEC_Timer_Control_Mirror);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef no_cpu
|
||||
|
||||
/* cpu.h */
|
||||
@@ -421,13 +437,16 @@ initialized +=
|
||||
(sizeof _TOD_Days_to_date) +
|
||||
(sizeof _TOD_Days_since_last_leap_year);
|
||||
|
||||
#ifdef sparc
|
||||
|
||||
initialized += (sizeof _CPU_Trap_slot_template);
|
||||
|
||||
#endif
|
||||
|
||||
puts( "" );
|
||||
#ifdef i960CA
|
||||
print_formula();
|
||||
#else
|
||||
|
||||
if ( mode == 0 ) help_size();
|
||||
else print_formula();
|
||||
#endif
|
||||
|
||||
printf( "\n" );
|
||||
printf( "RTEMS uninitialized data consumes %d bytes\n", uninitialized );
|
||||
|
||||
@@ -198,7 +198,7 @@ rtems_task test_task(
|
||||
end_time = Read_timer();
|
||||
|
||||
put_time(
|
||||
"rtems_task_set_note",
|
||||
"rtems_task_get_note",
|
||||
end_time,
|
||||
OPERATION_COUNT,
|
||||
overhead,
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING!!!!!!!!!
|
||||
*
|
||||
* THIS TEST USES INTERNAL RTEMS VARIABLES!!!
|
||||
*/
|
||||
|
||||
#define TEST_INIT
|
||||
#include "system.h"
|
||||
|
||||
@@ -33,15 +39,6 @@ rtems_isr Isr_handler(
|
||||
rtems_vector_number vector
|
||||
);
|
||||
|
||||
/*
|
||||
* INTERNAL RTEMS VARIABLES!!!
|
||||
*/
|
||||
|
||||
extern rtems_unsigned32 _Thread_Dispatch_disable_level;
|
||||
extern rtems_unsigned32 _Context_Switch_necessary;
|
||||
extern Chain_Control *_Thread_Ready_chain;
|
||||
extern rtems_tcb *_Thread_Heir;
|
||||
|
||||
rtems_task Init(
|
||||
rtems_task_argument argument
|
||||
)
|
||||
@@ -169,9 +166,23 @@ rtems_task Task_1(
|
||||
Interrupt_occurred = 0;
|
||||
Timer_initialize();
|
||||
Cause_tm27_intr();
|
||||
/* goes to Isr_handler */
|
||||
|
||||
/*
|
||||
* goes to Isr_handler and then returns
|
||||
*/
|
||||
|
||||
puts( "*** END OF TEST 27 ***" );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: When this task is executing, some of the assumptions made
|
||||
* regarding the placement of the currently executing task's TCB
|
||||
* on the ready chains have been violated. At least the assumption
|
||||
* that this task is at the head of the chain for its priority
|
||||
* has been violated.
|
||||
*/
|
||||
|
||||
rtems_task Task_2(
|
||||
rtems_task_argument argument
|
||||
)
|
||||
@@ -197,8 +208,20 @@ rtems_task Task_2(
|
||||
0
|
||||
);
|
||||
|
||||
puts( "*** END OF TEST 27 ***" );
|
||||
exit( 0 );
|
||||
fflush( stdout );
|
||||
|
||||
/*
|
||||
* Switch back to the other task to exit the test.
|
||||
*/
|
||||
|
||||
_Thread_Dispatch_disable_level = 0;
|
||||
|
||||
_Thread_Heir = (rtems_tcb *) _Thread_Ready_chain[254].first;
|
||||
|
||||
_Context_Switch_necessary = 1;
|
||||
|
||||
_Thread_Dispatch();
|
||||
|
||||
}
|
||||
|
||||
/* The Isr_handler() and Isr_handler_inner() routines are structured
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
#define __RINGBUF_H__
|
||||
|
||||
#ifndef RINGBUF_QUEUE_LENGTH
|
||||
#define RINGBUF_QUEUE_LENGTH 200
|
||||
#define RINGBUF_QUEUE_LENGTH 128
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char buffer[RINGBUF_QUEUE_LENGTH];
|
||||
int head;
|
||||
int tail;
|
||||
volatile int head;
|
||||
volatile int tail;
|
||||
} Ring_buffer_t;
|
||||
|
||||
#define Ring_buffer_Initialize( _buffer ) \
|
||||
@@ -27,16 +27,27 @@ typedef struct {
|
||||
#define Ring_buffer_Is_empty( _buffer ) \
|
||||
( (_buffer)->head == (_buffer)->tail )
|
||||
|
||||
#define Ring_buffer_Is_full( _buffer ) \
|
||||
( (_buffer)->head == ((_buffer)->tail + 1) % RINGBUF_QUEUE_LENGTH )
|
||||
|
||||
#define Ring_buffer_Add_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->tail = ((_buffer)->tail+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define Ring_buffer_Remove_character( _buffer, _ch ) \
|
||||
do { \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_unsigned32 isrlevel; \
|
||||
\
|
||||
rtems_interrupt_disable( isrlevel ); \
|
||||
(_buffer)->head = ((_buffer)->head+1) % RINGBUF_QUEUE_LENGTH; \
|
||||
(_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
|
||||
rtems_interrupt_enable( isrlevel ); \
|
||||
} while ( 0 )
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,8 +60,7 @@ EXTERN Objects_Information _POSIX_Interrupt_Handlers_Information;
|
||||
* interrupt handlers installed on each vector.
|
||||
*/
|
||||
|
||||
EXTERN POSIX_Interrupt_Control
|
||||
_POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
EXTERN POSIX_Interrupt_Control _POSIX_Interrupt_Information[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _POSIX_Interrupt_Manager_initialization
|
||||
|
||||
@@ -108,3 +108,205 @@ rtems_status_code rtems_event_receive(
|
||||
_Thread_Enable_dispatch();
|
||||
return( _Thread_Executing->Wait.return_code );
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Seize
|
||||
*
|
||||
* This routine attempts to satisfy the requested event condition
|
||||
* for the running thread.
|
||||
*
|
||||
* Input parameters:
|
||||
* event_in - the event condition to satisfy
|
||||
* option_set - acquire event options
|
||||
* ticks - interval to wait
|
||||
* event_out - pointer to event set output area
|
||||
*
|
||||
* Output parameters: NONE
|
||||
* *event_out - event set output area filled in
|
||||
*
|
||||
* INTERRUPT LATENCY:
|
||||
* available
|
||||
* wait
|
||||
* check sync
|
||||
*/
|
||||
|
||||
void _Event_Seize(
|
||||
rtems_event_set event_in,
|
||||
rtems_option option_set,
|
||||
rtems_interval ticks,
|
||||
rtems_event_set *event_out
|
||||
)
|
||||
{
|
||||
Thread_Control *executing;
|
||||
rtems_event_set seized_events;
|
||||
rtems_event_set pending_events;
|
||||
ISR_Level level;
|
||||
RTEMS_API_Control *api;
|
||||
|
||||
executing = _Thread_Executing;
|
||||
executing->Wait.return_code = RTEMS_SUCCESSFUL;
|
||||
|
||||
api = executing->API_Extensions[ THREAD_API_RTEMS ];
|
||||
|
||||
_ISR_Disable( level );
|
||||
pending_events = api->pending_events;
|
||||
seized_events = _Event_sets_Get( pending_events, event_in );
|
||||
|
||||
if ( !_Event_sets_Is_empty( seized_events ) &&
|
||||
(seized_events == event_in || _Options_Is_any( option_set )) ) {
|
||||
api->pending_events =
|
||||
_Event_sets_Clear( pending_events, seized_events );
|
||||
_ISR_Enable( level );
|
||||
*event_out = seized_events;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _Options_Is_no_wait( option_set ) ) {
|
||||
_ISR_Enable( level );
|
||||
executing->Wait.return_code = RTEMS_UNSATISFIED;
|
||||
*event_out = seized_events;
|
||||
return;
|
||||
}
|
||||
|
||||
_Event_Sync = TRUE;
|
||||
executing->Wait.option = (unsigned32) option_set;
|
||||
executing->Wait.count = (unsigned32) event_in;
|
||||
executing->Wait.return_argument = event_out;
|
||||
|
||||
_ISR_Enable( level );
|
||||
_Thread_Set_state( executing, STATES_WAITING_FOR_EVENT );
|
||||
|
||||
if ( ticks ) {
|
||||
_Watchdog_Initialize(
|
||||
&executing->Timer,
|
||||
_Event_Timeout,
|
||||
executing->Object.id,
|
||||
NULL
|
||||
);
|
||||
_Watchdog_Insert_ticks(
|
||||
&executing->Timer,
|
||||
ticks,
|
||||
WATCHDOG_NO_ACTIVATE
|
||||
);
|
||||
}
|
||||
|
||||
_ISR_Disable( level );
|
||||
if ( _Event_Sync == TRUE ) {
|
||||
_Event_Sync = FALSE;
|
||||
if ( ticks )
|
||||
_Watchdog_Activate( &executing->Timer );
|
||||
_ISR_Enable( level );
|
||||
return;
|
||||
}
|
||||
_ISR_Enable( level );
|
||||
(void) _Watchdog_Remove( &executing->Timer );
|
||||
_Thread_Unblock( executing );
|
||||
return;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Surrender
|
||||
*
|
||||
* This routines remove a thread from the specified threadq.
|
||||
*
|
||||
* Input parameters:
|
||||
* the_thread - pointer to thread to be dequeued
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*
|
||||
* INTERRUPT LATENCY:
|
||||
* before flash
|
||||
* after flash
|
||||
* check sync
|
||||
*/
|
||||
|
||||
void _Event_Surrender(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
ISR_Level level;
|
||||
rtems_event_set pending_events;
|
||||
rtems_event_set event_condition;
|
||||
rtems_event_set seized_events;
|
||||
rtems_option option_set;
|
||||
RTEMS_API_Control *api;
|
||||
|
||||
api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
|
||||
|
||||
option_set = (rtems_option) the_thread->Wait.option;
|
||||
|
||||
_ISR_Disable( level );
|
||||
pending_events = api->pending_events;
|
||||
event_condition = (rtems_event_set) the_thread->Wait.count;
|
||||
|
||||
seized_events = _Event_sets_Get( pending_events, event_condition );
|
||||
|
||||
if ( !_Event_sets_Is_empty( seized_events ) ) {
|
||||
if ( _States_Is_waiting_for_event( the_thread->current_state ) ) {
|
||||
if ( seized_events == event_condition || _Options_Is_any( option_set ) ) {
|
||||
api->pending_events =
|
||||
_Event_sets_Clear( pending_events, seized_events );
|
||||
*(rtems_event_set *)the_thread->Wait.return_argument = seized_events;
|
||||
|
||||
_ISR_Flash( level );
|
||||
|
||||
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
|
||||
_ISR_Enable( level );
|
||||
_Thread_Unblock( the_thread );
|
||||
}
|
||||
else {
|
||||
_Watchdog_Deactivate( &the_thread->Timer );
|
||||
_ISR_Enable( level );
|
||||
(void) _Watchdog_Remove( &the_thread->Timer );
|
||||
_Thread_Unblock( the_thread );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( _Thread_Is_executing( the_thread ) && _Event_Sync == TRUE ) {
|
||||
if ( seized_events == event_condition || _Options_Is_any( option_set ) ) {
|
||||
api->pending_events = _Event_sets_Clear( pending_events,seized_events );
|
||||
*(rtems_event_set *)the_thread->Wait.return_argument = seized_events;
|
||||
_Event_Sync = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ISR_Enable( level );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Event_Timeout
|
||||
*
|
||||
* This routine processes a thread which timeouts while waiting to
|
||||
* receive an event_set. It is called by the watchdog handler.
|
||||
*
|
||||
* Input parameters:
|
||||
* id - thread id
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*/
|
||||
|
||||
void _Event_Timeout(
|
||||
Objects_Id id,
|
||||
void *ignored
|
||||
)
|
||||
{
|
||||
Thread_Control *the_thread;
|
||||
Objects_Locations location;
|
||||
|
||||
the_thread = _Thread_Get( id, &location );
|
||||
switch ( location ) {
|
||||
case OBJECTS_ERROR:
|
||||
case OBJECTS_REMOTE: /* impossible */
|
||||
break;
|
||||
case OBJECTS_LOCAL:
|
||||
the_thread->Wait.return_code = RTEMS_TIMEOUT;
|
||||
_Thread_Unblock( the_thread );
|
||||
_Thread_Unnest_dispatch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
118
cpukit/score/cpu/sparc/README
Normal file
118
cpukit/score/cpu/sparc/README
Normal file
@@ -0,0 +1,118 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
This file discusses SPARC specific issues which are important to
|
||||
this port. The primary topics in this file are:
|
||||
|
||||
+ Global Register Usage
|
||||
+ Stack Frame
|
||||
+ EF bit in the PSR
|
||||
|
||||
|
||||
Global Register Usage
|
||||
=====================
|
||||
|
||||
This information on register usage is based heavily on a comment in the
|
||||
file gcc-2.7.0/config/sparc/sparc.h in the the gcc 2.7.0 source.
|
||||
|
||||
+ g0 is hardwired to 0
|
||||
+ On non-v9 systems:
|
||||
- g1 is free to use as temporary.
|
||||
- g2-g4 are reserved for applications. Gcc normally uses them as
|
||||
temporaries, but this can be disabled via the -mno-app-regs option.
|
||||
- g5 through g7 are reserved for the operating system.
|
||||
+ On v9 systems:
|
||||
- g1 and g5 are free to use as temporaries.
|
||||
- g2-g4 are reserved for applications (the compiler will not normally use
|
||||
them, but they can be used as temporaries with -mapp-regs).
|
||||
- g6-g7 are reserved for the operating system.
|
||||
|
||||
NOTE: As of gcc 2.7.0 register g1 was used in the following scenarios:
|
||||
|
||||
+ as a temporary by the 64 bit sethi pattern
|
||||
+ when restoring call-preserved registers in large stack frames
|
||||
|
||||
RTEMS places no constraints on the usage of the global registers. Although
|
||||
gcc assumes that either g5-g7 (non-V9) or g6-g7 (V9) are reserved for the
|
||||
operating system, RTEMS does not assume any special use for them.
|
||||
|
||||
|
||||
|
||||
Stack Frame
|
||||
===========
|
||||
|
||||
The stack grows downward (i.e. to lower addresses) on the SPARC architecture.
|
||||
|
||||
The following is the organization of the stack frame:
|
||||
|
||||
|
||||
|
||||
| ............... |
|
||||
fp | |
|
||||
+-------------------------------+
|
||||
| |
|
||||
| Local registers, temporaries, |
|
||||
| and saved floats | x bytes
|
||||
| |
|
||||
sp + x +-------------------------------+
|
||||
| |
|
||||
| outgoing parameters past |
|
||||
| the sixth one | x bytes
|
||||
| |
|
||||
sp + 92 +-------------------------------+ *
|
||||
| | *
|
||||
| area for callee to save | *
|
||||
| register arguments | * 24 bytes
|
||||
| | *
|
||||
sp + 68 +-------------------------------+ *
|
||||
| | *
|
||||
| structure return pointer | * 4 bytes
|
||||
| | *
|
||||
sp + 64 +-------------------------------+ *
|
||||
| | *
|
||||
| local register set | * 32 bytes
|
||||
| | *
|
||||
sp + 32 +-------------------------------+ *
|
||||
| | *
|
||||
| input register set | * 32 bytes
|
||||
| | *
|
||||
sp +-------------------------------+ *
|
||||
|
||||
|
||||
* = minimal stack frame
|
||||
|
||||
x = optional components
|
||||
|
||||
EF bit in the PSR
|
||||
=================
|
||||
|
||||
The EF (enable floating point unit) in the PSR is utilized in this port to
|
||||
prevent non-floating point tasks from performing floating point
|
||||
operations. This bit is maintained as part of the integer context.
|
||||
However, the floating point context is switched BEFORE the integer
|
||||
context. Thus the EF bit in place at the time of the FP switch may
|
||||
indicate that FP operations are disabled. This occurs on certain task
|
||||
switches, when the EF bit will be 0 for the outgoing task and thus a fault
|
||||
will be generated on the first FP operation of the FP context save.
|
||||
|
||||
The remedy for this is to enable FP access as the first step in both the
|
||||
save and restore of the FP context area. This bit will be subsequently
|
||||
reloaded by the integer context switch.
|
||||
|
||||
Two of the scenarios which demonstrate this problem are outlined below:
|
||||
|
||||
1. When the first FP task is switched to. The system tasks are not FP and
|
||||
thus would be unable to restore the FP context of the incoming task.
|
||||
|
||||
2. On a deferred FP context switch. In this case, the system might switch
|
||||
from FP Task A to non-FP Task B and then to FP Task C. In this scenario,
|
||||
the floating point state must technically be saved by a non-FP task.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
*/
|
||||
|
||||
#define ASM
|
||||
|
||||
#include <rtems/score/sparc.h>
|
||||
#include <rtems/score/cpu.h>
|
||||
|
||||
/*
|
||||
* Recent versions of GNU cpp define variables which indicate the
|
||||
@@ -37,7 +39,9 @@
|
||||
* have to define these as appropriate.
|
||||
*/
|
||||
|
||||
/* XXX This does not appear to work on gcc 2.7.0 on the sparc */
|
||||
/* XXX __USER_LABEL_PREFIX__ and __REGISTER_PREFIX__ do not work on gcc 2.7.0 */
|
||||
/* XXX The following ifdef magic fixes the problem but results in a warning */
|
||||
/* XXX when compiling assembly code. */
|
||||
#undef __USER_LABEL_PREFIX__
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__ _
|
||||
@@ -91,6 +95,16 @@
|
||||
#define PUBLIC(sym) .globl SYM (sym)
|
||||
#define EXTERN(sym) .globl SYM (sym)
|
||||
|
||||
/*
|
||||
* Entry for traps which jump to a programmer-specified trap handler.
|
||||
*/
|
||||
|
||||
#define TRAP(_vector, _handler) \
|
||||
mov %psr, %l0 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
mov _vector, %l3
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
|
||||
@@ -7,52 +7,115 @@
|
||||
#include <rtems/system.h>
|
||||
#include <rtems/score/isr.h>
|
||||
|
||||
/* _CPU_Initialize
|
||||
#if defined(erc32)
|
||||
#include <erc32.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This initializes the set of opcodes placed in each trap
|
||||
* table entry. The routine which installs a handler is responsible
|
||||
* for filling in the fields for the _handler address and the _vector
|
||||
* trap type.
|
||||
*
|
||||
* The constants following this structure are masks for the fields which
|
||||
* must be filled in when the handler is installed.
|
||||
*/
|
||||
|
||||
const CPU_Trap_table_entry _CPU_Trap_slot_template = {
|
||||
0xa1480000, /* mov %psr, %l0 */
|
||||
0x29000000, /* sethi %hi(_handler), %l4 */
|
||||
0x81c52000, /* jmp %l4 + %lo(_handler) */
|
||||
0xa6102000 /* mov _vector, %l3 */
|
||||
};
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Initialize
|
||||
*
|
||||
* This routine performs processor dependent initialization.
|
||||
*
|
||||
* INPUT PARAMETERS:
|
||||
* Input Parameters:
|
||||
* cpu_table - CPU table to initialize
|
||||
* thread_dispatch - address of disptaching routine
|
||||
*
|
||||
* Output Parameters: NONE
|
||||
*
|
||||
* NOTE: There is no need to save the pointer to the thread dispatch routine.
|
||||
* The SPARC's assembly code can reference it directly with no problems.
|
||||
*/
|
||||
|
||||
|
||||
void _CPU_Initialize(
|
||||
rtems_cpu_table *cpu_table,
|
||||
void (*thread_dispatch) /* ignored on this CPU */
|
||||
)
|
||||
{
|
||||
void *pointer;
|
||||
unsigned32 trap_table_start;
|
||||
unsigned32 tbr_value;
|
||||
CPU_Trap_table_entry *old_tbr;
|
||||
CPU_Trap_table_entry *trap_table;
|
||||
|
||||
/*
|
||||
* The thread_dispatch argument is the address of the entry point
|
||||
* for the routine called at the end of an ISR once it has been
|
||||
* decided a context switch is necessary. On some compilation
|
||||
* systems it is difficult to call a high-level language routine
|
||||
* from assembly. This allows us to trick these systems.
|
||||
*
|
||||
* If you encounter this problem save the entry point in a CPU
|
||||
* dependent variable.
|
||||
* Install the executive's trap table. All entries from the original
|
||||
* trap table are copied into the executive's trap table. This is essential
|
||||
* since this preserves critical trap handlers such as the window underflow
|
||||
* and overflow handlers. It is the responsibility of the BSP to provide
|
||||
* install these in the initial trap table.
|
||||
*/
|
||||
|
||||
_CPU_Thread_dispatch_pointer = thread_dispatch;
|
||||
trap_table_start = (unsigned32) &_CPU_Trap_Table_area;
|
||||
if (trap_table_start & (SPARC_TRAP_TABLE_ALIGNMENT-1))
|
||||
trap_table_start = (trap_table_start + SPARC_TRAP_TABLE_ALIGNMENT) &
|
||||
~(SPARC_TRAP_TABLE_ALIGNMENT-1);
|
||||
|
||||
trap_table = (CPU_Trap_table_entry *) trap_table_start;
|
||||
|
||||
sparc_get_tbr( tbr_value );
|
||||
|
||||
old_tbr = (CPU_Trap_table_entry *) (tbr_value & 0xfffff000);
|
||||
|
||||
memcpy( trap_table, (void *) old_tbr, 256 * sizeof( CPU_Trap_table_entry ) );
|
||||
|
||||
sparc_set_tbr( trap_table_start );
|
||||
|
||||
/*
|
||||
* If there is not an easy way to initialize the FP context
|
||||
* during Context_Initialize, then it is usually easier to
|
||||
* save an "uninitialized" FP context here and copy it to
|
||||
* the task's during Context_Initialize.
|
||||
* This seems to be the most appropriate way to obtain an initial
|
||||
* FP context on the SPARC. The NULL fp context is copied it to
|
||||
* the task's FP context during Context_Initialize.
|
||||
*/
|
||||
|
||||
pointer = &_CPU_Null_fp_context;
|
||||
_CPU_Context_save_fp( &pointer );
|
||||
|
||||
/*
|
||||
* Grab our own copy of the user's CPU table.
|
||||
*/
|
||||
|
||||
_CPU_Table = *cpu_table;
|
||||
|
||||
#if defined(erc32)
|
||||
|
||||
/*
|
||||
* ERC32 specific initialization
|
||||
*/
|
||||
|
||||
_ERC32_MEC_Timer_Control_Mirror = 0;
|
||||
ERC32_MEC.Timer_Control = 0;
|
||||
|
||||
ERC32_MEC.Control |= ERC32_CONFIGURATION_POWER_DOWN_ALLOWED;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_Get_level
|
||||
*
|
||||
* Input Parameters: NONE
|
||||
*
|
||||
* Output Parameters:
|
||||
* returns the current interrupt level (PIL field of the PSR)
|
||||
*/
|
||||
|
||||
unsigned32 _CPU_ISR_Get_level( void )
|
||||
@@ -64,134 +127,263 @@ unsigned32 _CPU_ISR_Get_level( void )
|
||||
return level;
|
||||
}
|
||||
|
||||
/* _CPU_ISR_install_vector
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_install_raw_handler
|
||||
*
|
||||
* This routine installs the specified handler as a "raw" non-executive
|
||||
* supported trap handler (a.k.a. interrupt service routine).
|
||||
*
|
||||
* Input Parameters:
|
||||
* vector - trap table entry number plus synchronous
|
||||
* vs. asynchronous information
|
||||
* new_handler - address of the handler to be installed
|
||||
* old_handler - pointer to an address of the handler previously installed
|
||||
*
|
||||
* Output Parameters: NONE
|
||||
* *new_handler - address of the handler previously installed
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* On the SPARC, there are really only 256 vectors. However, the executive
|
||||
* has no easy, fast, reliable way to determine which traps are synchronous
|
||||
* and which are asynchronous. By default, synchronous traps return to the
|
||||
* instruction which caused the interrupt. So if you install a software
|
||||
* trap handler as an executive interrupt handler (which is desirable since
|
||||
* RTEMS takes care of window and register issues), then the executive needs
|
||||
* to know that the return address is to the trap rather than the instruction
|
||||
* following the trap.
|
||||
*
|
||||
* So vectors 0 through 255 are treated as regular asynchronous traps which
|
||||
* provide the "correct" return address. Vectors 256 through 512 are assumed
|
||||
* by the executive to be synchronous and to require that the return address
|
||||
* be fudged.
|
||||
*
|
||||
* If you use this mechanism to install a trap handler which must reexecute
|
||||
* the instruction which caused the trap, then it should be installed as
|
||||
* an asynchronous trap. This will avoid the executive changing the return
|
||||
* address.
|
||||
*/
|
||||
|
||||
void _CPU_ISR_install_raw_handler(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
)
|
||||
{
|
||||
unsigned32 real_vector;
|
||||
CPU_Trap_table_entry *tbr;
|
||||
CPU_Trap_table_entry *slot;
|
||||
unsigned32 u32_tbr;
|
||||
unsigned32 u32_handler;
|
||||
|
||||
/*
|
||||
* Get the "real" trap number for this vector ignoring the synchronous
|
||||
* versus asynchronous indicator included with our vector numbers.
|
||||
*/
|
||||
|
||||
real_vector = SPARC_REAL_TRAP_NUMBER( vector );
|
||||
|
||||
/*
|
||||
* Get the current base address of the trap table and calculate a pointer
|
||||
* to the slot we are interested in.
|
||||
*/
|
||||
|
||||
sparc_get_tbr( u32_tbr );
|
||||
|
||||
u32_tbr &= 0xfffff000;
|
||||
|
||||
tbr = (CPU_Trap_table_entry *) u32_tbr;
|
||||
|
||||
slot = &tbr[ real_vector ];
|
||||
|
||||
/*
|
||||
* Get the address of the old_handler from the trap table.
|
||||
*
|
||||
* NOTE: The old_handler returned will be bogus if it does not follow
|
||||
* the RTEMS model.
|
||||
*/
|
||||
|
||||
#define HIGH_BITS_MASK 0xFFFFFC00
|
||||
#define HIGH_BITS_SHIFT 10
|
||||
#define LOW_BITS_MASK 0x000003FF
|
||||
|
||||
if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
|
||||
u32_handler =
|
||||
((slot->sethi_of_handler_to_l4 & HIGH_BITS_MASK) << HIGH_BITS_SHIFT) |
|
||||
(slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
|
||||
*old_handler = (proc_ptr) u32_handler;
|
||||
} else
|
||||
*old_handler = 0;
|
||||
|
||||
/*
|
||||
* Copy the template to the slot and then fix it.
|
||||
*/
|
||||
|
||||
*slot = _CPU_Trap_slot_template;
|
||||
|
||||
u32_handler = (unsigned32) new_handler;
|
||||
|
||||
slot->mov_vector_l3 |= vector;
|
||||
slot->sethi_of_handler_to_l4 |=
|
||||
(u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
|
||||
slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ISR_install_vector
|
||||
*
|
||||
* This kernel routine installs the RTEMS handler for the
|
||||
* specified vector.
|
||||
*
|
||||
* Input parameters:
|
||||
* vector - interrupt vector number
|
||||
* old_handler - former ISR for this vector number
|
||||
* new_handler - replacement ISR for this vector number
|
||||
* old_handler - pointer to former ISR for this vector number
|
||||
*
|
||||
* Output parameters: NONE
|
||||
* Output parameters:
|
||||
* *old_handler - former ISR for this vector number
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void _CPU_ISR_install_vector(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
)
|
||||
{
|
||||
*old_handler = _ISR_Vector_table[ vector ];
|
||||
unsigned32 real_vector;
|
||||
proc_ptr ignored;
|
||||
|
||||
/*
|
||||
* If the interrupt vector table is a table of pointer to isr entry
|
||||
* points, then we need to install the appropriate RTEMS interrupt
|
||||
* handler for this vector number.
|
||||
* Get the "real" trap number for this vector ignoring the synchronous
|
||||
* versus asynchronous indicator included with our vector numbers.
|
||||
*/
|
||||
|
||||
real_vector = SPARC_REAL_TRAP_NUMBER( vector );
|
||||
|
||||
/*
|
||||
* Return the previous ISR handler.
|
||||
*/
|
||||
|
||||
*old_handler = _ISR_Vector_table[ real_vector ];
|
||||
|
||||
/*
|
||||
* Install the wrapper so this ISR can be invoked properly.
|
||||
*/
|
||||
|
||||
_CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
|
||||
|
||||
/*
|
||||
* We put the actual user ISR address in '_ISR_vector_table'. This will
|
||||
* be used by the _ISR_Handler so the user gets control.
|
||||
*/
|
||||
|
||||
_ISR_Vector_table[ vector ] = new_handler;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Install_interrupt_stack
|
||||
*/
|
||||
|
||||
void _CPU_Install_interrupt_stack( void )
|
||||
{
|
||||
_ISR_Vector_table[ real_vector ] = new_handler;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_Context_Initialize
|
||||
*
|
||||
* This kernel routine initializes the basic non-FP context area associated
|
||||
* with each thread.
|
||||
*
|
||||
* Input parameters:
|
||||
* the_context - pointer to the context area
|
||||
* stack_base - address of memory for the SPARC
|
||||
* size - size in bytes of the stack area
|
||||
* new_level - interrupt level for this context area
|
||||
* entry_point - the starting execution point for this this context
|
||||
* is_fp - TRUE if this context is associated with an FP thread
|
||||
*
|
||||
* Output parameters: NONE
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following constants assist in building a thread's initial context.
|
||||
*/
|
||||
|
||||
#define CPU_FRAME_SIZE (112) /* based on disassembled test code */
|
||||
#define ADDR_ADJ_OFFSET -8
|
||||
|
||||
void _CPU_Context_Initialize(
|
||||
Context_Control *_the_context,
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
Context_Control *the_context,
|
||||
unsigned32 *stack_base,
|
||||
unsigned32 size,
|
||||
unsigned32 new_level,
|
||||
void *entry_point,
|
||||
boolean is_fp
|
||||
)
|
||||
{
|
||||
unsigned32 jmp_addr;
|
||||
unsigned32 _stack_high; /* highest "stack aligned" address */
|
||||
unsigned32 _the_size;
|
||||
unsigned32 stack_high; /* highest "stack aligned" address */
|
||||
unsigned32 the_size;
|
||||
unsigned32 tmp_psr;
|
||||
|
||||
jmp_addr = (unsigned32) _entry_point;
|
||||
|
||||
/*
|
||||
* On CPUs with stacks which grow down (i.e. SPARC), we build the stack
|
||||
* based on the _stack_high address.
|
||||
* based on the stack_high address.
|
||||
*/
|
||||
|
||||
_stack_high = ((unsigned32)(_stack_base) + _size);
|
||||
_stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
|
||||
stack_high = ((unsigned32)(stack_base) + size);
|
||||
stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
|
||||
|
||||
_the_size = _size & ~(CPU_STACK_ALIGNMENT - 1);
|
||||
the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
|
||||
|
||||
/* XXX following code is based on unix port */
|
||||
/*
|
||||
* XXX SPARC port needs a diagram like this one...
|
||||
* See /usr/include/sys/stack.h in Solaris 2.3 for a nice
|
||||
* diagram of the stack.
|
||||
* See the README in this directory for a diagram of the stack.
|
||||
*/
|
||||
|
||||
_the_context->o7 = jmp_addr + ADDR_ADJ_OFFSET;
|
||||
_the_context->o6 = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
|
||||
_the_context->i6 = (unsigned32)(_stack_high);
|
||||
#if 0
|
||||
_the_context->rp = jmp_addr + ADDR_ADJ_OFFSET;
|
||||
_the_context->sp = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
|
||||
_the_context->fp = (unsigned32)(_stack_high);
|
||||
#endif
|
||||
the_context->o7 = ((unsigned32) entry_point) - 8;
|
||||
the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
|
||||
the_context->i6_fp = stack_high;
|
||||
|
||||
_the_context->wim = 0x01;
|
||||
/*
|
||||
* Build the PSR for the task. Most everything can be 0 and the
|
||||
* CWP is corrected during the context switch.
|
||||
*
|
||||
* The EF bit determines if the floating point unit is available.
|
||||
* The FPU is ONLY enabled if the context is associated with an FP task
|
||||
* and this SPARC model has an FPU.
|
||||
*/
|
||||
|
||||
sparc_get_psr( tmp_psr );
|
||||
tmp_psr &= ~SPARC_PIL_MASK;
|
||||
tmp_psr |= (((_new_level) << 8) & SPARC_PIL_MASK);
|
||||
tmp_psr = (tmp_psr & ~0x07) | 0x07; /* XXX should use num windows */
|
||||
_the_context->psr = tmp_psr;
|
||||
tmp_psr &= ~SPARC_PSR_PIL_MASK;
|
||||
tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
|
||||
tmp_psr &= ~SPARC_PSR_EF_MASK; /* disabled by default */
|
||||
|
||||
#if (SPARC_HAS_FPU == 1)
|
||||
/*
|
||||
* If this bit is not set, then a task gets a fault when it accesses
|
||||
* a floating point register. This is a nice way to detect floating
|
||||
* point tasks which are not currently declared as such.
|
||||
*/
|
||||
|
||||
if ( is_fp )
|
||||
tmp_psr |= SPARC_PSR_EF_MASK;
|
||||
#endif
|
||||
the_context->psr = tmp_psr;
|
||||
}
|
||||
|
||||
/*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.
|
||||
* Some SPARC implementations have low power, sleep, or idle modes. This
|
||||
* tries to take advantage of those models.
|
||||
*/
|
||||
|
||||
#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
|
||||
|
||||
/*
|
||||
* This is the implementation for the erc32.
|
||||
*
|
||||
* NOTE: Low power mode was enabled at initialization time.
|
||||
*/
|
||||
|
||||
#if defined(erc32)
|
||||
|
||||
void _CPU_Internal_threads_Idle_thread_body( void )
|
||||
{
|
||||
|
||||
for( ; ; )
|
||||
/* insert your "halt" instruction here */ ;
|
||||
while (1) {
|
||||
ERC32_MEC.Power_Down = 0; /* value is irrelevant */
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
*/
|
||||
|
||||
#define ASM
|
||||
|
||||
#include <rtems/score/sparc.h>
|
||||
#include <rtems/score/cpu.h>
|
||||
|
||||
/*
|
||||
* Recent versions of GNU cpp define variables which indicate the
|
||||
@@ -37,7 +39,9 @@
|
||||
* have to define these as appropriate.
|
||||
*/
|
||||
|
||||
/* XXX This does not appear to work on gcc 2.7.0 on the sparc */
|
||||
/* XXX __USER_LABEL_PREFIX__ and __REGISTER_PREFIX__ do not work on gcc 2.7.0 */
|
||||
/* XXX The following ifdef magic fixes the problem but results in a warning */
|
||||
/* XXX when compiling assembly code. */
|
||||
#undef __USER_LABEL_PREFIX__
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__ _
|
||||
@@ -91,6 +95,16 @@
|
||||
#define PUBLIC(sym) .globl SYM (sym)
|
||||
#define EXTERN(sym) .globl SYM (sym)
|
||||
|
||||
/*
|
||||
* Entry for traps which jump to a programmer-specified trap handler.
|
||||
*/
|
||||
|
||||
#define TRAP(_vector, _handler) \
|
||||
mov %psr, %l0 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
mov _vector, %l3
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
|
||||
@@ -341,17 +341,10 @@ void _CPU_Install_interrupt_stack( void )
|
||||
*
|
||||
* _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.
|
||||
* Stop until we get a signal which is the logically the same thing
|
||||
* entering low-power or sleep mode on a real processor and waiting for
|
||||
* an interrupt. This significantly reduces the consumption of host
|
||||
* CPU cycles which is again similar to low power mode.
|
||||
*/
|
||||
|
||||
void _CPU_Internal_threads_Idle_thread_body( void )
|
||||
@@ -370,7 +363,8 @@ void _CPU_Context_Initialize(
|
||||
unsigned32 *_stack_base,
|
||||
unsigned32 _size,
|
||||
unsigned32 _new_level,
|
||||
void *_entry_point
|
||||
void *_entry_point,
|
||||
boolean _is_fp
|
||||
)
|
||||
{
|
||||
void *source;
|
||||
@@ -697,49 +691,15 @@ void _CPU_Fatal_error(unsigned32 error)
|
||||
_exit(error);
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _CPU_ffs
|
||||
*/
|
||||
|
||||
int _CPU_ffs(unsigned32 value)
|
||||
{
|
||||
int output;
|
||||
extern int ffs( int );
|
||||
|
||||
output = ffs(value);
|
||||
output = output - 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Special Purpose Routines to hide the use of UNIX system calls.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* XXX clock had this set of #define's */
|
||||
|
||||
/*
|
||||
* In order to get the types and prototypes used in this file under
|
||||
* Solaris 2.3, it is necessary to pull the following magic.
|
||||
*/
|
||||
|
||||
#if defined(solaris)
|
||||
#warning "Ignore the undefining __STDC__ warning"
|
||||
#undef __STDC__
|
||||
#define __STDC__ 0
|
||||
#undef _POSIX_C_SOURCE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int _CPU_Get_clock_vector( void )
|
||||
{
|
||||
return SIGALRM;
|
||||
}
|
||||
|
||||
|
||||
void _CPU_Start_clock(
|
||||
int microseconds
|
||||
)
|
||||
|
||||
@@ -38,9 +38,58 @@ extern "C" {
|
||||
* significant impact on the performance of the executive as a whole.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_DATA == TRUE )
|
||||
|
||||
#ifndef INIT
|
||||
extern const unsigned char __log2table[256];
|
||||
#else
|
||||
const unsigned char __log2table[256] = {
|
||||
7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == FALSE )
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
_CPU_Bitfield_Find_first_bit( _value, _bit_number )
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* The following must be a macro because if a CPU specific version
|
||||
* is used it will most likely use inline assembly.
|
||||
*/
|
||||
|
||||
#define _Bitfield_Find_first_bit( _value, _bit_number ) \
|
||||
{ \
|
||||
register __value = (_value); \
|
||||
register const unsigned char *__p = __log2table; \
|
||||
\
|
||||
if ( __value < 0x100 ) \
|
||||
(_bit_number) = __p[ __value ] + 8; \
|
||||
else \
|
||||
(_bit_number) = __p[ __value >> 8 ]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,8 +47,9 @@ EXTERN boolean _Context_Switch_necessary;
|
||||
* thread's initial state.
|
||||
*/
|
||||
|
||||
#define _Context_Initialize( _the_context, _stack, _size, _isr, _entry ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry )
|
||||
#define \
|
||||
_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp ) \
|
||||
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp )
|
||||
|
||||
/*
|
||||
* _Context_Switch
|
||||
|
||||
@@ -50,12 +50,19 @@ typedef ISR_Handler ( *ISR_Handler_entry )(
|
||||
ISR_Vector_number
|
||||
);
|
||||
/*
|
||||
* This constant promotes out the number of vectors supported by
|
||||
* the current CPU being used.
|
||||
* This constant promotes out the number of vectors truly supported by
|
||||
* the current CPU being used. This is usually the number of distinct vectors
|
||||
* the cpu can vector.
|
||||
*/
|
||||
|
||||
#define ISR_NUMBER_OF_VECTORS CPU_INTERRUPT_NUMBER_OF_VECTORS
|
||||
|
||||
/*
|
||||
* This constant promotes out the highest valid interrupt vector number.
|
||||
*/
|
||||
|
||||
#define ISR_INTERRUPT_MAXIMUM_VECTOR_NUMBER CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER
|
||||
|
||||
/*
|
||||
* The following is TRUE if signals have been sent to the currently
|
||||
* executing thread by an ISR handler.
|
||||
@@ -75,7 +82,7 @@ EXTERN unsigned32 _ISR_Nest_level;
|
||||
* interrupt service routines are vectored by the ISR Handler via this table.
|
||||
*/
|
||||
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[CPU_INTERRUPT_NUMBER_OF_VECTORS];
|
||||
EXTERN ISR_Handler_entry _ISR_Vector_table[ ISR_NUMBER_OF_VECTORS ];
|
||||
|
||||
/*
|
||||
* _ISR_Handler_initialization
|
||||
|
||||
@@ -113,6 +113,51 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
Priority_Control the_priority
|
||||
);
|
||||
|
||||
/*
|
||||
* _Priority_Mask
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function returns the mask associated with the major or minor
|
||||
* number passed to it.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
_CPU_Priority_Mask( _bit_number )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* This function translates the bit numbers returned by the bit scan
|
||||
* of a priority bit field into something suitable for use as
|
||||
* a major or minor component of a priority.
|
||||
*/
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
#define _Priority_Bits_index( _priority ) \
|
||||
_CPU_Priority_bits_index( _priority )
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _Priority_Add_to_bit_map
|
||||
*
|
||||
|
||||
@@ -38,7 +38,7 @@ STATIC INLINE boolean _ISR_Is_vector_number_valid (
|
||||
unsigned32 vector
|
||||
)
|
||||
{
|
||||
return ( vector < CPU_INTERRUPT_NUMBER_OF_VECTORS );
|
||||
return ( vector <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
|
||||
@@ -78,6 +78,37 @@ STATIC INLINE unsigned32 _Priority_Minor (
|
||||
return ( the_priority % 16 );
|
||||
}
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Mask (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return (0x8000 >> bit_number);
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
STATIC INLINE unsigned32 _Priority_Bits_index (
|
||||
unsigned32 bit_number
|
||||
)
|
||||
{
|
||||
return bit_number;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -121,8 +152,8 @@ STATIC INLINE Priority_Control _Priority_Get_highest( void )
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major );
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor );
|
||||
|
||||
return (_CPU_Priority_Bits_index( major ) << 4) +
|
||||
_CPU_Priority_Bits_index( minor );
|
||||
return (_Priority_Bits_index( major ) << 4) +
|
||||
_Priority_Bits_index( minor );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -144,13 +175,13 @@ STATIC INLINE void _Priority_Initialize_information(
|
||||
minor = _Priority_Minor( new_priority );
|
||||
|
||||
the_priority_map->minor =
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(major) ];
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(major) ];
|
||||
|
||||
mask = _CPU_Priority_Mask( major );
|
||||
mask = _Priority_Mask( major );
|
||||
the_priority_map->ready_major = mask;
|
||||
the_priority_map->block_major = ~mask;
|
||||
|
||||
mask = _CPU_Priority_Mask( minor );
|
||||
mask = _Priority_Mask( minor );
|
||||
the_priority_map->ready_minor = mask;
|
||||
the_priority_map->block_minor = ~mask;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#define _ISR_Is_vector_number_valid( _vector ) \
|
||||
( (_vector) < CPU_INTERRUPT_NUMBER_OF_VECTORS )
|
||||
( (_vector) <= CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
|
||||
@@ -64,6 +64,28 @@
|
||||
|
||||
#define _Priority_Minor( _the_priority ) ( (_the_priority) % 16 )
|
||||
|
||||
#if ( CPU_USE_GENERIC_BITFIELD_CODE == TRUE )
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Mask
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Mask( _bit_number ) \
|
||||
(0x8000 >> _bit_number)
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Bits_index
|
||||
*
|
||||
*/
|
||||
|
||||
#define _Priority_Bits_index( _bit_number ) \
|
||||
(_bit_number)
|
||||
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* _Priority_Add_to_bit_map
|
||||
@@ -103,8 +125,8 @@
|
||||
_Bitfield_Find_first_bit( _Priority_Major_bit_map, major ); \
|
||||
_Bitfield_Find_first_bit( _Priority_Bit_map[major], minor ); \
|
||||
\
|
||||
(_high_priority) = (_CPU_Priority_Bits_index( major ) * 16) + \
|
||||
_CPU_Priority_Bits_index( minor ); \
|
||||
(_high_priority) = (_Priority_Bits_index( major ) * 16) + \
|
||||
_Priority_Bits_index( minor ); \
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
@@ -124,13 +146,13 @@
|
||||
_minor = _Priority_Minor( (_new_priority) ); \
|
||||
\
|
||||
(_the_priority_map)->minor = \
|
||||
&_Priority_Bit_map[ _CPU_Priority_Bits_index(_major) ]; \
|
||||
&_Priority_Bit_map[ _Priority_Bits_index(_major) ]; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _major ); \
|
||||
_mask = _Priority_Mask( _major ); \
|
||||
(_the_priority_map)->ready_major = _mask; \
|
||||
(_the_priority_map)->block_major = ~_mask; \
|
||||
\
|
||||
_mask = _CPU_Priority_Mask( _minor ); \
|
||||
_mask = _Priority_Mask( _minor ); \
|
||||
(_the_priority_map)->ready_minor = _mask; \
|
||||
(_the_priority_map)->block_minor = ~_mask; \
|
||||
}
|
||||
|
||||
@@ -805,9 +805,12 @@ void _Thread_Load_environment(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
boolean is_fp = FALSE;
|
||||
|
||||
if ( the_thread->Start.fp_context ) {
|
||||
the_thread->fp_context = the_thread->Start.fp_context;
|
||||
_Context_Initialize_fp( &the_thread->fp_context );
|
||||
is_fp = TRUE;
|
||||
}
|
||||
|
||||
the_thread->is_preemptible = the_thread->Start.is_preemptible;
|
||||
@@ -818,7 +821,8 @@ void _Thread_Load_environment(
|
||||
the_thread->Start.Initial_stack.area,
|
||||
the_thread->Start.Initial_stack.size,
|
||||
the_thread->Start.isr_level,
|
||||
_Thread_Handler
|
||||
_Thread_Handler,
|
||||
is_fp
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user