mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 23:23:13 +00:00
274 lines
7.0 KiB
C
274 lines
7.0 KiB
C
/* Altivec support for RTEMS; vector register context management. */
|
|
|
|
/*
|
|
* Authorship
|
|
* ----------
|
|
* This software was created by
|
|
* Till Straumann <strauman@slac.stanford.edu>, 2009,
|
|
* Stanford Linear Accelerator Center, Stanford University.
|
|
*
|
|
* Acknowledgement of sponsorship
|
|
* ------------------------------
|
|
* This software was produced by
|
|
* the Stanford Linear Accelerator Center, Stanford University,
|
|
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
|
*
|
|
* Government disclaimer of liability
|
|
* ----------------------------------
|
|
* Neither the United States nor the United States Department of Energy,
|
|
* nor any of their employees, makes any warranty, express or implied, or
|
|
* assumes any legal liability or responsibility for the accuracy,
|
|
* completeness, or usefulness of any data, apparatus, product, or process
|
|
* disclosed, or represents that its use would not infringe privately owned
|
|
* rights.
|
|
*
|
|
* Stanford disclaimer of liability
|
|
* --------------------------------
|
|
* Stanford University makes no representations or warranties, express or
|
|
* implied, nor assumes any liability for the use of this software.
|
|
*
|
|
* Stanford disclaimer of copyright
|
|
* --------------------------------
|
|
* Stanford University, owner of the copyright, hereby disclaims its
|
|
* copyright and all other rights in this software. Hence, anyone may
|
|
* freely use it for any purpose without restriction.
|
|
*
|
|
* Maintenance of notices
|
|
* ----------------------
|
|
* In the interest of clarity regarding the origin and status of this
|
|
* SLAC software, this and all the preceding Stanford University notices
|
|
* are to remain affixed to any copy or derivative of this software made
|
|
* or distributed by the recipient and are to be affixed to any copy of
|
|
* software made or distributed by the recipient that contains a copy or
|
|
* derivative of this software.
|
|
*
|
|
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
|
*/
|
|
|
|
#ifdef __ALTIVEC__
|
|
|
|
#include <rtems.h>
|
|
#include <libcpu/cpuIdent.h>
|
|
#include <rtems/bspIo.h>
|
|
#include <rtems/error.h>
|
|
#include <rtems/score/cpu.h>
|
|
#include <rtems/powerpc/powerpc.h>
|
|
|
|
#define STATIC static
|
|
|
|
#define VEC_ALIGNMENT 16
|
|
|
|
#define NAM "AltiVec Support"
|
|
#define ERRID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | (d))
|
|
|
|
typedef uint32_t _vu32 __attribute__((vector_size(VEC_ALIGNMENT)));
|
|
|
|
#ifndef MSR_VE
|
|
#define MSR_VE (1<<(31-6))
|
|
#endif
|
|
|
|
/* NOTE: These two variables are accessed by assembly code
|
|
* which assumes 32-bit data!
|
|
*/
|
|
uint32_t _CPU_altivec_ctxt_off = 0;
|
|
uint32_t _CPU_altivec_psim_cpu = 0;
|
|
|
|
static inline uint32_t
|
|
mfmsr(void)
|
|
{
|
|
uint32_t v;
|
|
_CPU_MSR_GET(v);
|
|
return v;
|
|
}
|
|
|
|
static inline void
|
|
mtmsr(uint32_t v)
|
|
{
|
|
_CPU_MSR_SET(v);
|
|
}
|
|
|
|
static inline void
|
|
isync(void)
|
|
{
|
|
asm volatile("isync");
|
|
}
|
|
|
|
static inline void
|
|
dssall(void)
|
|
{
|
|
if ( !_CPU_altivec_psim_cpu)
|
|
asm volatile("dssall");
|
|
}
|
|
|
|
static inline uint32_t
|
|
set_MSR_VE(void)
|
|
{
|
|
uint32_t rval;
|
|
rval=mfmsr();
|
|
if ( ! (MSR_VE & rval ) ) {
|
|
mtmsr(rval | MSR_VE);
|
|
isync();
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
static inline void
|
|
clr_MSR_VE(void)
|
|
{
|
|
dssall();
|
|
mtmsr(mfmsr() & ~MSR_VE);
|
|
isync();
|
|
}
|
|
|
|
static inline void
|
|
rst_MSR_VE(uint32_t old)
|
|
{
|
|
if ( ! ( MSR_VE & old ) ) {
|
|
dssall();
|
|
mtmsr(old);
|
|
isync();
|
|
}
|
|
}
|
|
|
|
|
|
/* Code to probe the compiler's stack alignment (PowerPC);
|
|
* The routine determines at run-time if the compiler generated
|
|
* 8 or 16-byte aligned code.
|
|
*
|
|
* Till Straumann <strauman@slac.stanford.edu>, 2005
|
|
*/
|
|
|
|
static void dummy(void) __attribute__((noinline));
|
|
/* add (empty) asm-statement to make sure this isn't optimized away */
|
|
static void dummy(void) { __asm__ volatile(""); }
|
|
|
|
static unsigned probe_r1(void) __attribute__((noinline));
|
|
static unsigned probe_r1(void)
|
|
{
|
|
unsigned r1;
|
|
/* call something to enforce creation of a minimal stack frame;
|
|
* (8 bytes: r1 and lr space for 'dummy' callee). If compiled
|
|
* with -meabi -mno-altivec gcc allocates 8 bytes, if -mno-eabi
|
|
* or -maltivec / -mabi=altivec then gcc allocates 16 bytes
|
|
* according to the sysv / altivec ABI specs.
|
|
*/
|
|
dummy();
|
|
/* return stack pointer */
|
|
asm volatile("mr %0,1":"=r"(r1));
|
|
return r1;
|
|
}
|
|
|
|
static unsigned
|
|
probe_ppc_stack_alignment(void)
|
|
{
|
|
unsigned r1;
|
|
asm volatile("mr %0,1":"=r"(r1));
|
|
return (r1 - probe_r1()) & ~ 0xf;
|
|
}
|
|
|
|
STATIC int check_stack_alignment(void)
|
|
{
|
|
int rval = 0;
|
|
if ( VEC_ALIGNMENT > PPC_STACK_ALIGNMENT ) {
|
|
printk(NAM": CPU support has unsufficient stack alignment;\n");
|
|
printk("modify 'cpukit/score/cpu/powerpc/rtems/score/powerpc.h'\n");
|
|
printk("and choose PPC_ABI_SVR4. I'll enable a workaround for now.\n");
|
|
rval |= 1;
|
|
}
|
|
/* Run-time check; should compile with -mabi=altivec */
|
|
if ( probe_ppc_stack_alignment() < VEC_ALIGNMENT ) {
|
|
printk(NAM": run-time stack alignment unsufficient; make sure you compile with -mabi=altivec\n");
|
|
rval |= 2;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
|
|
static uint32_t probe_vrsave(_vu32 *p_v) __attribute__((noinline));
|
|
|
|
/* Check if this code was compiled with -mvrsave=yes or no
|
|
* so that we can set the default/init value accordingly.
|
|
*/
|
|
static uint32_t probe_vrsave(_vu32 *p_v)
|
|
{
|
|
_vu32 x;
|
|
uint32_t vrsave;
|
|
/* Explicitly clobber a volatile vector reg (0) that is
|
|
* not used to pass return values.
|
|
* If -mvrsave=yes was used this should cause gcc to
|
|
* set bit 0 in vrsave. OTOH this bit cannot be set
|
|
* because v0 is volatile and not used to pass a value
|
|
* to the caller...
|
|
*/
|
|
asm volatile("vxor %0, 0, 0; mfvrsave %1":"=v"(x),"=r"(vrsave)::"v0");
|
|
if ( p_v ) {
|
|
*p_v = x;
|
|
}
|
|
return vrsave;
|
|
}
|
|
|
|
static int vrsave_yes(void) __attribute__((noinline));
|
|
|
|
static int vrsave_yes(void)
|
|
{
|
|
uint32_t vrsave_pre;
|
|
asm volatile("mfvrsave %0":"=r"(vrsave_pre));
|
|
if ( (vrsave_pre & 0x80000000) ) {
|
|
printk(NAM": WARNING - unable to determine whether -mvrsave was used; assuming NO\n");
|
|
return 0;
|
|
}
|
|
return probe_vrsave(0) != vrsave_pre;
|
|
}
|
|
|
|
extern void
|
|
_CPU_altivec_set_vrsave_initval(uint32_t);
|
|
|
|
|
|
void
|
|
_CPU_Initialize_altivec(void)
|
|
{
|
|
unsigned pvr;
|
|
|
|
/* I don't like to have to #define the offset of the altivec area
|
|
* for use by assembly code.
|
|
* Therefore, we compute it here and store it in memory...
|
|
*/
|
|
_CPU_altivec_ctxt_off = offsetof(ppc_context, altivec);
|
|
|
|
/*
|
|
* See ppc_get_context() and PPC_CONTEXT_OFFSET_GPR1
|
|
*/
|
|
_CPU_altivec_ctxt_off += PPC_DEFAULT_CACHE_LINE_SIZE;
|
|
|
|
/*
|
|
* Add space possibly needed for alignment
|
|
*/
|
|
_CPU_altivec_ctxt_off += PPC_CACHE_ALIGNMENT - 1;
|
|
|
|
if ( ! vrsave_yes() ) {
|
|
/* They seemed to compile with -mvrsave=no. Hence we
|
|
* must set VRSAVE so that all registers are saved/restored
|
|
* in case this support was not built with IGNORE_VRSAVE.
|
|
*/
|
|
_CPU_altivec_set_vrsave_initval( -1 );
|
|
}
|
|
|
|
if ( check_stack_alignment() & 2 )
|
|
rtems_fatal_error_occurred(ERRID('V','E','C','1'));
|
|
|
|
pvr = get_ppc_cpu_type();
|
|
/* psim has altivec but lacks the streaming instructions :-( */
|
|
_CPU_altivec_psim_cpu = (PPC_PSIM == pvr);
|
|
|
|
if ( ! ppc_cpu_has_altivec() ) {
|
|
printk(NAM": This CPU seems not to have AltiVec\n");
|
|
rtems_panic("Unable to initialize AltiVec Support\n");
|
|
}
|
|
|
|
if ( ! (mfmsr() & MSR_VE) ) {
|
|
printk(NAM": Warning: BSP should set MSR_VE early; doing it now...\n");
|
|
set_MSR_VE();
|
|
}
|
|
}
|
|
#endif
|